CIRCT  18.0.0git
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"
23 #include "circt/Support/LLVM.h"
24 #include "mlir/IR/BuiltinOps.h"
25 #include "mlir/IR/BuiltinTypes.h"
26 #include "mlir/IR/Diagnostics.h"
27 #include "mlir/IR/ImplicitLocOpBuilder.h"
28 #include "mlir/IR/Threading.h"
29 #include "mlir/IR/Verifier.h"
30 #include "mlir/Support/Timing.h"
31 #include "mlir/Tools/mlir-translate/Translation.h"
32 #include "llvm/ADT/PointerEmbeddedInt.h"
33 #include "llvm/ADT/STLExtras.h"
34 #include "llvm/ADT/SmallPtrSet.h"
35 #include "llvm/ADT/StringExtras.h"
36 #include "llvm/ADT/StringSet.h"
37 #include "llvm/ADT/StringSwitch.h"
38 #include "llvm/ADT/TypeSwitch.h"
39 #include "llvm/Support/JSON.h"
40 #include "llvm/Support/SourceMgr.h"
41 #include "llvm/Support/raw_ostream.h"
42 #include <memory>
43 
44 using namespace circt;
45 using namespace firrtl;
46 using namespace chirrtl;
47 
48 using llvm::SMLoc;
49 using llvm::SourceMgr;
50 using mlir::LocationAttr;
51 
52 namespace json = llvm::json;
53 
54 //===----------------------------------------------------------------------===//
55 // SharedParserConstants
56 //===----------------------------------------------------------------------===//
57 
58 namespace {
59 
60 /// This class refers to immutable values and annotations maintained globally by
61 /// the parser which can be referred to by any active parser, even those running
62 /// in parallel. This is shared by all active parsers.
63 struct SharedParserConstants {
64  SharedParserConstants(MLIRContext *context, FIRParserOptions options)
65  : context(context), options(options),
66  emptyArrayAttr(ArrayAttr::get(context, {})),
67  loIdentifier(StringAttr::get(context, "lo")),
68  hiIdentifier(StringAttr::get(context, "hi")),
69  amountIdentifier(StringAttr::get(context, "amount")),
70  fieldIndexIdentifier(StringAttr::get(context, "fieldIndex")),
71  indexIdentifier(StringAttr::get(context, "index")) {}
72 
73  /// The context we're parsing into.
74  MLIRContext *const context;
75 
76  // Options that control the behavior of the parser.
77  const FIRParserOptions options;
78 
79  /// A map from identifiers to type aliases.
80  llvm::StringMap<FIRRTLType> aliasMap;
81 
82  /// A map from identifiers to class ops.
83  llvm::DenseMap<StringRef, ClassLike> classMap;
84 
85  /// An empty array attribute.
86  const ArrayAttr emptyArrayAttr;
87 
88  /// Cached identifiers used in primitives.
89  const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
90  const StringAttr fieldIndexIdentifier, indexIdentifier;
91 
92 private:
93  SharedParserConstants(const SharedParserConstants &) = delete;
94  void operator=(const SharedParserConstants &) = delete;
95 };
96 
97 } // end anonymous namespace
98 
99 //===----------------------------------------------------------------------===//
100 // FIRParser
101 //===----------------------------------------------------------------------===//
102 
103 namespace {
104 /// This class implements logic common to all levels of the parser, including
105 /// things like types and helper logic.
106 struct FIRParser {
107  FIRParser(SharedParserConstants &constants, FIRLexer &lexer,
108  FIRVersion version)
109  : version(version), constants(constants), lexer(lexer),
110  locatorFilenameCache(constants.loIdentifier /*arbitrary non-null id*/) {
111  }
112 
113  // Helper methods to get stuff from the shared parser constants.
114  SharedParserConstants &getConstants() const { return constants; }
115  MLIRContext *getContext() const { return constants.context; }
116 
117  FIRLexer &getLexer() { return lexer; }
118 
119  /// Return the indentation level of the specified token.
120  std::optional<unsigned> getIndentation() const {
121  return lexer.getIndentation(getToken());
122  }
123 
124  /// Return the current token the parser is inspecting.
125  const FIRToken &getToken() const { return lexer.getToken(); }
126  StringRef getTokenSpelling() const { return getToken().getSpelling(); }
127 
128  //===--------------------------------------------------------------------===//
129  // Error Handling
130  //===--------------------------------------------------------------------===//
131 
132  /// Emit an error and return failure.
133  InFlightDiagnostic emitError(const Twine &message = {}) {
134  return emitError(getToken().getLoc(), message);
135  }
136  InFlightDiagnostic emitError(SMLoc loc, const Twine &message = {});
137 
138  /// Emit a warning.
139  InFlightDiagnostic emitWarning(const Twine &message = {}) {
140  return emitWarning(getToken().getLoc(), message);
141  }
142 
143  InFlightDiagnostic emitWarning(SMLoc loc, const Twine &message = {});
144 
145  //===--------------------------------------------------------------------===//
146  // Location Handling
147  //===--------------------------------------------------------------------===//
148 
149  class LocWithInfo;
150 
151  /// Encode the specified source location information into an attribute for
152  /// attachment to the IR.
153  Location translateLocation(llvm::SMLoc loc) {
154  return lexer.translateLocation(loc);
155  }
156 
157  /// Parse an @info marker if present. If so, fill in the specified Location,
158  /// if not, ignore it.
159  ParseResult parseOptionalInfoLocator(LocationAttr &result);
160 
161  /// Parse an optional name that may appear in Stop, Printf, or Verification
162  /// statements.
163  ParseResult parseOptionalName(StringAttr &name);
164 
165  //===--------------------------------------------------------------------===//
166  // Version and Feature Checking
167  //===--------------------------------------------------------------------===//
168 
169  ParseResult requireFeature(FIRVersion minimum, StringRef feature) {
170  if (version < minimum)
171  return emitError() << feature << " are a FIRRTL " << minimum
172  << "+ feature, but the specified FIRRTL version was "
173  << version;
174  return success();
175  }
176 
177  //===--------------------------------------------------------------------===//
178  // Annotation Parsing
179  //===--------------------------------------------------------------------===//
180 
181  /// Parse a non-standard inline Annotation JSON blob if present. This uses
182  /// the info-like encoding of %[<JSON Blob>].
183  ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
184 
185  //===--------------------------------------------------------------------===//
186  // Token Parsing
187  //===--------------------------------------------------------------------===//
188 
189  /// If the current token has the specified kind, consume it and return true.
190  /// If not, return false.
191  bool consumeIf(FIRToken::Kind kind) {
192  if (getToken().isNot(kind))
193  return false;
194  consumeToken(kind);
195  return true;
196  }
197 
198  /// Advance the current lexer onto the next token.
199  ///
200  /// This returns the consumed token.
201  FIRToken consumeToken() {
202  FIRToken consumedToken = getToken();
203  assert(consumedToken.isNot(FIRToken::eof, FIRToken::error) &&
204  "shouldn't advance past EOF or errors");
205  lexer.lexToken();
206  return consumedToken;
207  }
208 
209  /// Advance the current lexer onto the next token, asserting what the expected
210  /// current token is. This is preferred to the above method because it leads
211  /// to more self-documenting code with better checking.
212  ///
213  /// This returns the consumed token.
214  FIRToken consumeToken(FIRToken::Kind kind) {
215  FIRToken consumedToken = getToken();
216  assert(consumedToken.is(kind) && "consumed an unexpected token");
217  consumeToken();
218  return consumedToken;
219  }
220 
221  /// Capture the current token's spelling into the specified value. This
222  /// always succeeds.
223  ParseResult parseGetSpelling(StringRef &spelling) {
224  spelling = getTokenSpelling();
225  return success();
226  }
227 
228  /// Consume the specified token if present and return success. On failure,
229  /// output a diagnostic and return failure.
230  ParseResult parseToken(FIRToken::Kind expectedToken, const Twine &message);
231 
232  /// Parse a list of elements, terminated with an arbitrary token.
233  ParseResult parseListUntil(FIRToken::Kind rightToken,
234  const std::function<ParseResult()> &parseElement);
235 
236  //===--------------------------------------------------------------------===//
237  // Common Parser Rules
238  //===--------------------------------------------------------------------===//
239 
240  /// Parse 'intLit' into the specified value.
241  ParseResult parseIntLit(APInt &result, const Twine &message);
242  ParseResult parseIntLit(int64_t &result, const Twine &message);
243  ParseResult parseIntLit(int32_t &result, const Twine &message);
244 
245  // Parse 'verLit' into specified value
246  ParseResult parseVersionLit(const Twine &message);
247 
248  // Parse ('<' intLit '>')? setting result to -1 if not present.
249  template <typename T>
250  ParseResult parseOptionalWidth(T &result);
251 
252  // Parse the 'id' grammar, which is an identifier or an allowed keyword.
253  ParseResult parseId(StringRef &result, const Twine &message);
254  ParseResult parseId(StringAttr &result, const Twine &message);
255  ParseResult parseFieldId(StringRef &result, const Twine &message);
256  ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
257  const Twine &message);
258  ParseResult parseEnumType(FIRRTLType &result);
259  ParseResult parseListType(FIRRTLType &result);
260  ParseResult parseMapType(FIRRTLType &result);
261  ParseResult parseType(FIRRTLType &result, const Twine &message);
262  // Parse a property type specifically.
263  ParseResult parsePropertyType(PropertyType &result, const Twine &message);
264 
265  ParseResult parseOptionalRUW(RUWAttr &result);
266 
267  /// The version of FIRRTL to use for this parser.
268  FIRVersion version;
269 
270 private:
271  FIRParser(const FIRParser &) = delete;
272  void operator=(const FIRParser &) = delete;
273 
274  /// FIRParser is subclassed and reinstantiated. Do not add additional
275  /// non-trivial state here, add it to SharedParserConstants.
276  SharedParserConstants &constants;
277  FIRLexer &lexer;
278 
279  /// This is a single-entry cache for filenames in locators.
280  StringAttr locatorFilenameCache;
281  /// This is a single-entry cache for FileLineCol locations.
282  FileLineColLoc fileLineColLocCache;
283 };
284 
285 } // end anonymous namespace
286 
287 //===----------------------------------------------------------------------===//
288 // Error Handling
289 //===----------------------------------------------------------------------===//
290 
291 InFlightDiagnostic FIRParser::emitError(SMLoc loc, const Twine &message) {
292  auto diag = mlir::emitError(translateLocation(loc), message);
293 
294  // If we hit a parse error in response to a lexer error, then the lexer
295  // already reported the error.
296  if (getToken().is(FIRToken::error))
297  diag.abandon();
298  return diag;
299 }
300 
301 InFlightDiagnostic FIRParser::emitWarning(SMLoc loc, const Twine &message) {
302  return mlir::emitWarning(translateLocation(loc), message);
303 }
304 
305 //===----------------------------------------------------------------------===//
306 // Token Parsing
307 //===----------------------------------------------------------------------===//
308 
309 /// Consume the specified token if present and return success. On failure,
310 /// output a diagnostic and return failure.
311 ParseResult FIRParser::parseToken(FIRToken::Kind expectedToken,
312  const Twine &message) {
313  if (consumeIf(expectedToken))
314  return success();
315  return emitError(message);
316 }
317 
318 /// Parse a list of elements, terminated with an arbitrary token.
319 ParseResult
320 FIRParser::parseListUntil(FIRToken::Kind rightToken,
321  const std::function<ParseResult()> &parseElement) {
322 
323  while (!consumeIf(rightToken)) {
324  if (parseElement())
325  return failure();
326  }
327  return success();
328 }
329 
330 //===--------------------------------------------------------------------===//
331 // Location Processing
332 //===--------------------------------------------------------------------===//
333 
334 /// This helper class is used to handle Info records, which specify higher level
335 /// symbolic source location, that may be missing from the file. If the higher
336 /// level source information is missing, we fall back to the location in the
337 /// .fir file.
339 public:
340  explicit LocWithInfo(SMLoc firLoc, FIRParser *parser)
341  : parser(parser), firLoc(firLoc) {}
342 
343  SMLoc getFIRLoc() const { return firLoc; }
344 
345  Location getLoc() {
346  if (infoLoc)
347  return *infoLoc;
348  auto result = parser->translateLocation(firLoc);
349  infoLoc = result;
350  return result;
351  }
352 
353  /// Parse an @info marker if present and update our location.
354  ParseResult parseOptionalInfo() {
355  LocationAttr loc;
356  if (failed(parser->parseOptionalInfoLocator(loc)))
357  return failure();
358  if (loc) {
360  switch (parser->constants.options.infoLocatorHandling) {
361  case ILH::IgnoreInfo:
362  assert(0 && "Should not return info locations if ignoring");
363  break;
364  case ILH::PreferInfo:
365  infoLoc = loc;
366  break;
367  case ILH::FusedInfo:
368  infoLoc = FusedLoc::get(loc.getContext(),
369  {loc, parser->translateLocation(firLoc)});
370  break;
371  }
372  }
373  return success();
374  }
375 
376  /// If we didn't parse an info locator for the specified value, this sets a
377  /// default, overriding a fall back to a location in the .fir file.
378  void setDefaultLoc(Location loc) {
379  if (!infoLoc)
380  infoLoc = loc;
381  }
382 
383 private:
384  FIRParser *const parser;
385 
386  /// This is the designated location in the .fir file for use when there is no
387  /// @ info marker.
388  SMLoc firLoc;
389 
390  /// This is the location specified by the @ marker if present.
391  std::optional<Location> infoLoc;
392 };
393 
394 /// Parse an @info marker if present. If so, fill in the specified Location,
395 /// if not, ignore it.
396 ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
397  if (getToken().isNot(FIRToken::fileinfo))
398  return success();
399 
400  auto loc = getToken().getLoc();
401 
402  auto spelling = getTokenSpelling();
403  consumeToken(FIRToken::fileinfo);
404 
405  auto locationPair = maybeStringToLocation(
406  spelling,
407  constants.options.infoLocatorHandling ==
409  locatorFilenameCache, fileLineColLocCache, getContext());
410 
411  // If parsing failed, then indicate that a weird info was found.
412  if (!locationPair.first) {
413  mlir::emitWarning(translateLocation(loc),
414  "ignoring unknown @ info record format");
415  return success();
416  }
417 
418  // If the parsing succeeded, but we are supposed to drop locators, then just
419  // return.
420  if (locationPair.first && constants.options.infoLocatorHandling ==
422  return success();
423 
424  // Otherwise, set the location attribute and return.
425  result = *locationPair.second;
426  return success();
427 }
428 
429 /// Parse an optional trailing name that may show up on assert, assume, cover,
430 /// stop, or printf.
431 ///
432 /// optional_name ::= ( ':' id )?
433 ParseResult FIRParser::parseOptionalName(StringAttr &name) {
434 
435  if (getToken().isNot(FIRToken::colon)) {
436  name = StringAttr::get(getContext(), "");
437  return success();
438  }
439 
440  consumeToken(FIRToken::colon);
441  StringRef nameRef;
442  if (parseId(nameRef, "expected result name"))
443  return failure();
444 
445  name = StringAttr::get(getContext(), nameRef);
446 
447  return success();
448 }
449 
450 //===--------------------------------------------------------------------===//
451 // Annotation Handling
452 //===--------------------------------------------------------------------===//
453 
454 /// Parse a non-standard inline Annotation JSON blob if present. This uses
455 /// the info-like encoding of %[<JSON Blob>].
456 ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
457 
458  if (getToken().isNot(FIRToken::inlineannotation))
459  return success();
460 
461  loc = getToken().getLoc();
462 
463  result = getTokenSpelling().drop_front(2).drop_back(1);
464  consumeToken(FIRToken::inlineannotation);
465 
466  return success();
467 }
468 
469 //===--------------------------------------------------------------------===//
470 // Common Parser Rules
471 //===--------------------------------------------------------------------===//
472 
473 /// intLit ::= UnsignedInt
474 /// ::= SignedInt
475 /// ::= HexLit
476 /// ::= OctalLit
477 /// ::= BinaryLit
478 /// HexLit ::= '"' 'h' ( '+' | '-' )? ( HexDigit )+ '"'
479 /// OctalLit ::= '"' 'o' ( '+' | '-' )? ( OctalDigit )+ '"'
480 /// BinaryLit ::= '"' 'b' ( '+' | '-' )? ( BinaryDigit )+ '"'
481 ///
482 ParseResult FIRParser::parseIntLit(APInt &result, const Twine &message) {
483  auto spelling = getTokenSpelling();
484  bool isNegative = false;
485  switch (getToken().getKind()) {
486  case FIRToken::signed_integer:
487  isNegative = spelling[0] == '-';
488  assert(spelling[0] == '+' || spelling[0] == '-');
489  spelling = spelling.drop_front();
490  [[fallthrough]];
491  case FIRToken::integer:
492  if (spelling.getAsInteger(10, result))
493  return emitError(message), failure();
494 
495  // Make sure that the returned APInt has a zero at the top so clients don't
496  // confuse it with a negative number.
497  if (result.isNegative())
498  result = result.zext(result.getBitWidth() + 1);
499 
500  if (isNegative)
501  result = -result;
502 
503  // If this was parsed as >32 bits, but can be represented in 32 bits,
504  // truncate off the extra width. This is important for extmodules which
505  // like parameters to be 32-bits, and insulates us from some arbitraryness
506  // in StringRef::getAsInteger.
507  if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
508  result = result.trunc(32);
509 
510  consumeToken();
511  return success();
512  case FIRToken::radix_specified_integer: {
513  if (requireFeature({2, 4, 0}, "radix-specified integer literals"))
514  return failure();
515  if (spelling[0] == '-') {
516  isNegative = true;
517  spelling = spelling.drop_front();
518  }
519  unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
520  .Case("0b", 2)
521  .Case("0o", 8)
522  .Case("0d", 10)
523  .Case("0h", 16);
524  spelling = spelling.drop_front(2);
525  if (spelling.getAsInteger(base, result))
526  return emitError("invalid character in integer literal"), failure();
527  if (result.isNegative())
528  result = result.zext(result.getBitWidth() + 1);
529  if (isNegative)
530  result = -result;
531  consumeToken();
532  return success();
533  }
534  case FIRToken::string: {
535  if (FIRVersion(3, 0, 0) <= version)
536  return emitError(
537  "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
538 
539  // Drop the quotes.
540  assert(spelling.front() == '"' && spelling.back() == '"');
541  spelling = spelling.drop_back().drop_front();
542 
543  // Decode the base.
544  unsigned base;
545  switch (spelling.empty() ? ' ' : spelling.front()) {
546  case 'h':
547  base = 16;
548  break;
549  case 'o':
550  base = 8;
551  break;
552  case 'b':
553  base = 2;
554  break;
555  default:
556  return emitError("expected base specifier (h/o/b) in integer literal"),
557  failure();
558  }
559  spelling = spelling.drop_front();
560 
561  // Handle the optional sign.
562  bool isNegative = false;
563  if (!spelling.empty() && spelling.front() == '+')
564  spelling = spelling.drop_front();
565  else if (!spelling.empty() && spelling.front() == '-') {
566  isNegative = true;
567  spelling = spelling.drop_front();
568  }
569 
570  // Parse the digits.
571  if (spelling.empty())
572  return emitError("expected digits in integer literal"), failure();
573 
574  if (spelling.getAsInteger(base, result))
575  return emitError("invalid character in integer literal"), failure();
576 
577  // We just parsed the positive version of this number. Make sure it has
578  // a zero at the top so clients don't confuse it with a negative number and
579  // so the negation (in the case of a negative sign) doesn't overflow.
580  if (result.isNegative())
581  result = result.zext(result.getBitWidth() + 1);
582 
583  if (isNegative)
584  result = -result;
585 
586  consumeToken(FIRToken::string);
587  return success();
588  }
589 
590  default:
591  return emitError("expected integer literal"), failure();
592  }
593 }
594 
595 ParseResult FIRParser::parseIntLit(int64_t &result, const Twine &message) {
596  APInt value;
597  auto loc = getToken().getLoc();
598  if (parseIntLit(value, message))
599  return failure();
600 
601  result = (int64_t)value.getLimitedValue(INT64_MAX);
602  if (result != value)
603  return emitError(loc, "value is too big to handle"), failure();
604  return success();
605 }
606 
607 ParseResult FIRParser::parseIntLit(int32_t &result, const Twine &message) {
608  APInt value;
609  auto loc = getToken().getLoc();
610  if (parseIntLit(value, message))
611  return failure();
612 
613  result = (int32_t)value.getLimitedValue(INT32_MAX);
614  if (result != value)
615  return emitError(loc, "value is too big to handle"), failure();
616  return success();
617 }
618 
619 /// versionLit ::= version
620 /// deconstruct a version literal into parts and returns those.
621 ParseResult FIRParser::parseVersionLit(const Twine &message) {
622  auto spelling = getTokenSpelling();
623  if (getToken().getKind() != FIRToken::version)
624  return emitError(message), failure();
625  // form a.b.c
626  auto [a, d] = spelling.split(".");
627  auto [b, c] = d.split(".");
628  APInt aInt, bInt, cInt;
629  if (a.getAsInteger(10, aInt) || b.getAsInteger(10, bInt) ||
630  c.getAsInteger(10, cInt))
631  return emitError("failed to parse version string"), failure();
632  version.major = aInt.getLimitedValue(UINT32_MAX);
633  version.minor = bInt.getLimitedValue(UINT32_MAX);
634  version.patch = cInt.getLimitedValue(UINT32_MAX);
635  if (version.major != aInt || version.minor != bInt || version.patch != cInt)
636  return emitError("integers out of range"), failure();
637  if (version < minimumFIRVersion)
638  return emitError() << "FIRRTL version must be >=" << minimumFIRVersion,
639  failure();
640  consumeToken(FIRToken::version);
641  return success();
642 }
643 
644 // optional-width ::= ('<' intLit '>')?
645 //
646 // This returns with result equal to -1 if not present.
647 template <typename T>
648 ParseResult FIRParser::parseOptionalWidth(T &result) {
649  if (!consumeIf(FIRToken::less))
650  return result = -1, success();
651 
652  // Parse a width specifier if present.
653  auto widthLoc = getToken().getLoc();
654  if (parseIntLit(result, "expected width") ||
655  parseToken(FIRToken::greater, "expected >"))
656  return failure();
657 
658  if (result < 0)
659  return emitError(widthLoc, "invalid width specifier"), failure();
660 
661  return success();
662 }
663 
664 /// id ::= Id | keywordAsId
665 ///
666 /// Parse the 'id' grammar, which is an identifier or an allowed keyword. On
667 /// success, this returns the identifier in the result attribute.
668 ParseResult FIRParser::parseId(StringRef &result, const Twine &message) {
669  switch (getToken().getKind()) {
670  // The most common case is an identifier.
671  case FIRToken::identifier:
672  case FIRToken::literal_identifier:
673 // Otherwise it may be a keyword that we're allowing in an id position.
674 #define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
675 #include "FIRTokenKinds.def"
676 
677  // Yep, this is a valid identifier or literal identifier. Turn it into an
678  // attribute. If it is a literal identifier, then drop the leading and
679  // trailing '`' (backticks).
680  if (getToken().getKind() == FIRToken::literal_identifier)
681  result = getTokenSpelling().drop_front().drop_back();
682  else
683  result = getTokenSpelling();
684  consumeToken();
685  return success();
686 
687  default:
688  emitError(message);
689  return failure();
690  }
691 }
692 
693 ParseResult FIRParser::parseId(StringAttr &result, const Twine &message) {
694  StringRef name;
695  if (parseId(name, message))
696  return failure();
697 
698  result = StringAttr::get(getContext(), name);
699  return success();
700 }
701 
702 /// fieldId ::= Id
703 /// ::= RelaxedId
704 /// ::= UnsignedInt
705 /// ::= keywordAsId
706 ///
707 ParseResult FIRParser::parseFieldId(StringRef &result, const Twine &message) {
708  // Handle the UnsignedInt case.
709  result = getTokenSpelling();
710  if (consumeIf(FIRToken::integer))
711  return success();
712 
713  // FIXME: Handle RelaxedId
714 
715  // Otherwise, it must be Id or keywordAsId.
716  if (parseId(result, message))
717  return failure();
718 
719  return success();
720 }
721 
722 /// fieldId ::= Id
723 /// ::= Float
724 /// ::= version
725 /// ::= UnsignedInt
726 /// ::= keywordAsId
727 ///
728 ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
729  const Twine &message) {
730  // Handle the UnsignedInt case.
731  StringRef tmp = getTokenSpelling();
732 
733  if (consumeIf(FIRToken::integer)) {
734  result.push_back(tmp);
735  return success();
736  }
737 
738  if (consumeIf(FIRToken::floatingpoint)) {
739  // form a.b
740  // Both a and b could have more floating point stuff, but just ignore that
741  // for now.
742  auto [a, b] = tmp.split(".");
743  result.push_back(a);
744  result.push_back(b);
745  return success();
746  }
747 
748  if (consumeIf(FIRToken::version)) {
749  // form a.b.c
750  auto [a, d] = tmp.split(".");
751  auto [b, c] = d.split(".");
752  result.push_back(a);
753  result.push_back(b);
754  result.push_back(c);
755  return success();
756  }
757 
758  // Otherwise, it must be Id or keywordAsId.
759  if (parseId(tmp, message))
760  return failure();
761  result.push_back(tmp);
762  return success();
763 }
764 
765 /// enum-field ::= Id ( ':' type )? ;
766 /// enum-type ::= '{|' enum-field* '|}'
767 ParseResult FIRParser::parseEnumType(FIRRTLType &result) {
768  if (parseToken(FIRToken::l_brace_bar,
769  "expected leading '{|' in enumeration type"))
770  return failure();
771  SmallVector<FEnumType::EnumElement> elements;
772  if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
773  auto fieldLoc = getToken().getLoc();
774 
775  // Parse the name of the tag.
776  StringRef name;
777  if (parseId(name, "expected valid identifier for enumeration tag"))
778  return failure();
779 
780  // Parse an optional type ascription.
781  FIRRTLBaseType type;
782  if (consumeIf(FIRToken::colon)) {
783  FIRRTLType parsedType;
784  if (parseType(parsedType, "expected enumeration type"))
785  return failure();
786  type = type_dyn_cast<FIRRTLBaseType>(parsedType);
787  if (!type)
788  return emitError(fieldLoc, "field must be a base type");
789  } else {
790  // If there is no type specified, default to UInt<0>.
791  type = UIntType::get(getContext(), 0);
792  }
793  elements.emplace_back(StringAttr::get(getContext(), name), type);
794  return success();
795  }))
796  return failure();
797  result = FEnumType::get(getContext(), elements);
798  return success();
799 }
800 
801 ParseResult FIRParser::parsePropertyType(PropertyType &result,
802  const Twine &message) {
803  FIRRTLType type;
804  if (parseType(type, message))
805  return failure();
806  auto prop = type_dyn_cast<PropertyType>(type);
807  if (!prop)
808  return emitError("expected property type");
809  result = prop;
810  return success();
811 }
812 
813 /// list-type ::= 'List' '<' type '>'
814 ParseResult FIRParser::parseListType(FIRRTLType &result) {
815  consumeToken(FIRToken::kw_List);
816 
818  if (parseToken(FIRToken::less, "expected '<' in List type") ||
819  parsePropertyType(elementType, "expected List element type") ||
820  parseToken(FIRToken::greater, "expected '>' in List type"))
821  return failure();
822 
823  result = ListType::get(getContext(), elementType);
824  return success();
825 }
826 
827 /// map-type ::= 'Map' '<' type ',' type '>'
828 ParseResult FIRParser::parseMapType(FIRRTLType &result) {
829  consumeToken(FIRToken::kw_Map);
830 
831  PropertyType key, value;
832  if (parseToken(FIRToken::less, "expected '<' in Map type") ||
833  parsePropertyType(key, "expected Map key type") ||
834  parsePropertyType(value, "expected Map value type") ||
835  parseToken(FIRToken::greater, "expected '>' in Map type"))
836  return failure();
837 
838  result = MapType::get(getContext(), key, value);
839  return success();
840 }
841 
842 /// type ::= 'Clock'
843 /// ::= 'Reset'
844 /// ::= 'AsyncReset'
845 /// ::= 'UInt' optional-width
846 /// ::= 'SInt' optional-width
847 /// ::= 'Analog' optional-width
848 /// ::= {' field* '}'
849 /// ::= type '[' intLit ']'
850 /// ::= 'Probe' '<' type '>'
851 /// ::= 'RWProbe' '<' type '>'
852 /// ::= 'const' type
853 /// ::= 'String'
854 /// ::= list-type
855 /// ::= map-type
856 /// ::= id
857 ///
858 /// field: 'flip'? fieldId ':' type
859 ///
860 // NOLINTNEXTLINE(misc-no-recursion)
861 ParseResult FIRParser::parseType(FIRRTLType &result, const Twine &message) {
862  switch (getToken().getKind()) {
863  default:
864  return emitError(message), failure();
865 
866  case FIRToken::kw_Clock:
867  consumeToken(FIRToken::kw_Clock);
868  result = ClockType::get(getContext());
869  break;
870 
871  case FIRToken::kw_Inst: {
872  if (requireFeature({3, 2, 0}, "Inst types"))
873  return failure();
874 
875  consumeToken(FIRToken::kw_Inst);
876  if (parseToken(FIRToken::less, "expected < in Inst type"))
877  return failure();
878 
879  auto loc = getToken().getLoc();
880  StringRef id;
881  if (parseId(id, "expected class name in Inst type"))
882  return failure();
883 
884  // Look up the class that is being referenced.
885  const auto &classMap = getConstants().classMap;
886  auto lookup = classMap.find(id);
887  if (lookup == classMap.end())
888  return emitError(loc) << "unknown class '" << id << "'";
889 
890  auto classOp = lookup->second;
891 
892  if (parseToken(FIRToken::greater, "expected > in Inst type"))
893  return failure();
894 
895  result = classOp.getInstanceType();
896  break;
897  }
898 
899  case FIRToken::kw_AnyRef: {
900  if (requireFeature({3, 2, 0}, "AnyRef types"))
901  return failure();
902 
903  consumeToken(FIRToken::kw_AnyRef);
904  result = AnyRefType::get(getContext());
905  break;
906  }
907 
908  case FIRToken::kw_Reset:
909  consumeToken(FIRToken::kw_Reset);
910  result = ResetType::get(getContext());
911  break;
912 
913  case FIRToken::kw_AsyncReset:
914  consumeToken(FIRToken::kw_AsyncReset);
915  result = AsyncResetType::get(getContext());
916  break;
917 
918  case FIRToken::kw_UInt:
919  case FIRToken::kw_SInt:
920  case FIRToken::kw_Analog: {
921  auto kind = getToken().getKind();
922  consumeToken();
923 
924  // Parse a width specifier if present.
925  int32_t width;
926  if (parseOptionalWidth(width))
927  return failure();
928 
929  if (kind == FIRToken::kw_SInt)
930  result = SIntType::get(getContext(), width);
931  else if (kind == FIRToken::kw_UInt)
932  result = UIntType::get(getContext(), width);
933  else {
934  assert(kind == FIRToken::kw_Analog);
935  result = AnalogType::get(getContext(), width);
936  }
937  break;
938  }
939 
940  case FIRToken::kw_Probe:
941  case FIRToken::kw_RWProbe: {
942  auto kind = getToken().getKind();
943  auto loc = getToken().getLoc();
944  consumeToken();
945  FIRRTLType type;
946 
947  if (parseToken(FIRToken::less, "expected '<' in reference type") ||
948  parseType(type, "expected probe data type") ||
949  parseToken(FIRToken::greater, "expected '>' in reference type"))
950  return failure();
951 
952  bool forceable = kind == FIRToken::kw_RWProbe;
953 
954  auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
955  if (!innerType || innerType.containsReference())
956  return emitError(loc, "cannot nest reference types");
957 
958  if (!innerType.isPassive())
959  return emitError(loc, "probe inner type must be passive");
960 
961  if (forceable && innerType.containsConst())
962  return emitError(loc, "rwprobe cannot contain const");
963 
964  result = RefType::get(innerType, forceable);
965  break;
966  }
967 
968  case FIRToken::l_brace: {
969  consumeToken(FIRToken::l_brace);
970 
971  SmallVector<OpenBundleType::BundleElement, 4> elements;
972  bool bundleCompatible = true;
973  if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
974  bool isFlipped = consumeIf(FIRToken::kw_flip);
975 
976  StringRef fieldName;
977  FIRRTLType type;
978  if (parseFieldId(fieldName, "expected bundle field name") ||
979  parseToken(FIRToken::colon, "expected ':' in bundle"))
980  return failure();
981  if (parseType(type, "expected bundle field type"))
982  return failure();
983 
984  elements.push_back(
985  {StringAttr::get(getContext(), fieldName), isFlipped, type});
986  bundleCompatible &= isa<BundleType::ElementType>(type);
987  return success();
988  }))
989  return failure();
990 
991  // Try to emit base-only bundle.
992  if (bundleCompatible) {
993  auto bundleElements = llvm::map_range(elements, [](auto element) {
994  return BundleType::BundleElement{
995  element.name, element.isFlip,
996  cast<BundleType::ElementType>(element.type)};
997  });
998  result = BundleType::get(getContext(), llvm::to_vector(bundleElements));
999  } else
1000  result = OpenBundleType::get(getContext(), elements);
1001  break;
1002  }
1003 
1004  case FIRToken::l_brace_bar: {
1005  if (parseEnumType(result))
1006  return failure();
1007  break;
1008  }
1009 
1010  case FIRToken::identifier: {
1011  StringRef id;
1012  auto loc = getToken().getLoc();
1013  if (parseId(id, "expected a type alias name"))
1014  return failure();
1015  auto it = constants.aliasMap.find(id);
1016  if (it == constants.aliasMap.end()) {
1017  emitError(loc) << "type identifier `" << id << "` is not declared";
1018  return failure();
1019  }
1020  result = it->second;
1021  break;
1022  }
1023 
1024  case FIRToken::kw_const: {
1025  consumeToken(FIRToken::kw_const);
1026  auto nextToken = getToken();
1027  auto loc = nextToken.getLoc();
1028 
1029  // Guard against multiple 'const' specifications
1030  if (nextToken.is(FIRToken::kw_const))
1031  return emitError(loc, "'const' can only be specified once on a type");
1032 
1033  if (failed(parseType(result, message)))
1034  return failure();
1035 
1036  auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1037  if (!baseType)
1038  return emitError(loc, "only hardware types can be 'const'");
1039 
1040  result = baseType.getConstType(true);
1041  return success();
1042  }
1043 
1044  case FIRToken::kw_String:
1045  if (requireFeature({3, 1, 0}, "Strings"))
1046  return failure();
1047  consumeToken(FIRToken::kw_String);
1048  result = StringType::get(getContext());
1049  break;
1050  case FIRToken::kw_Integer:
1051  if (requireFeature({3, 1, 0}, "Integers"))
1052  return failure();
1053  consumeToken(FIRToken::kw_Integer);
1054  result = FIntegerType::get(getContext());
1055  break;
1056  case FIRToken::kw_Bool:
1057  if (requireFeature({3, 2, 0}, "Bools"))
1058  return failure();
1059  consumeToken(FIRToken::kw_Bool);
1060  result = BoolType::get(getContext());
1061  break;
1062  case FIRToken::kw_Double:
1063  if (requireFeature({3, 2, 0}, "Doubles"))
1064  return failure();
1065  consumeToken(FIRToken::kw_Double);
1066  result = DoubleType::get(getContext());
1067  break;
1068  case FIRToken::kw_Path:
1069  if (requireFeature({3, 1, 0}, "Paths"))
1070  return failure();
1071  consumeToken(FIRToken::kw_Path);
1072  result = PathType::get(getContext());
1073  break;
1074  case FIRToken::kw_List:
1075  if (requireFeature({3, 2, 0}, "Lists") || parseListType(result))
1076  return failure();
1077  break;
1078  case FIRToken::kw_Map:
1079  if (requireFeature({3, 2, 0}, "Maps") || parseMapType(result))
1080  return failure();
1081  break;
1082  }
1083 
1084  // Handle postfix vector sizes.
1085  while (consumeIf(FIRToken::l_square)) {
1086  auto sizeLoc = getToken().getLoc();
1087  int64_t size;
1088  if (parseIntLit(size, "expected width") ||
1089  parseToken(FIRToken::r_square, "expected ]"))
1090  return failure();
1091 
1092  if (size < 0)
1093  return emitError(sizeLoc, "invalid size specifier"), failure();
1094 
1095  auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1096  if (baseType)
1097  result = FVectorType::get(baseType, size);
1098  else
1099  result = OpenVectorType::get(result, size);
1100  }
1101 
1102  return success();
1103 }
1104 
1105 /// ruw ::= 'old' | 'new' | 'undefined'
1106 ParseResult FIRParser::parseOptionalRUW(RUWAttr &result) {
1107  switch (getToken().getKind()) {
1108  default:
1109  break;
1110 
1111  case FIRToken::kw_old:
1112  result = RUWAttr::Old;
1113  consumeToken(FIRToken::kw_old);
1114  break;
1115  case FIRToken::kw_new:
1116  result = RUWAttr::New;
1117  consumeToken(FIRToken::kw_new);
1118  break;
1119  case FIRToken::kw_undefined:
1120  result = RUWAttr::Undefined;
1121  consumeToken(FIRToken::kw_undefined);
1122  break;
1123  }
1124 
1125  return success();
1126 }
1127 
1128 //===----------------------------------------------------------------------===//
1129 // FIRModuleContext
1130 //===----------------------------------------------------------------------===//
1131 
1132 // Entries in a symbol table are either an mlir::Value for the operation that
1133 // defines the value or an unbundled ID tracking the index in the
1134 // UnbundledValues list.
1135 using UnbundledID = llvm::PointerEmbeddedInt<unsigned, 31>;
1136 using SymbolValueEntry = llvm::PointerUnion<Value, UnbundledID>;
1137 
1139  llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1140 using ModuleSymbolTableEntry = ModuleSymbolTable::MapEntryTy;
1141 
1142 using UnbundledValueEntry = SmallVector<std::pair<Attribute, Value>>;
1143 using UnbundledValuesList = std::vector<UnbundledValueEntry>;
1144 namespace {
1145 /// This structure is used to track which entries are added while inside a scope
1146 /// and remove them upon exiting the scope.
1147 struct UnbundledValueRestorer {
1148  UnbundledValuesList &list;
1149  size_t startingSize;
1150  UnbundledValueRestorer(UnbundledValuesList &list) : list(list) {
1151  startingSize = list.size();
1152  }
1153  ~UnbundledValueRestorer() { list.resize(startingSize); }
1154 };
1155 } // namespace
1156 
1157 using SubaccessCache = llvm::DenseMap<std::pair<Value, unsigned>, Value>;
1158 
1159 namespace {
1160 /// This struct provides context information that is global to the module we're
1161 /// currently parsing into.
1162 struct FIRModuleContext : public FIRParser {
1163  explicit FIRModuleContext(SharedParserConstants &constants, FIRLexer &lexer,
1164  FIRVersion version)
1165  : FIRParser(constants, lexer, version) {}
1166 
1167  // The expression-oriented nature of firrtl syntax produces tons of constant
1168  // nodes which are obviously redundant. Instead of literally producing them
1169  // in the parser, do an implicit CSE to reduce parse time and silliness in the
1170  // resulting IR.
1171  llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1172 
1173  /// Get a cached constant.
1174  Value getCachedConstantInt(ImplicitLocOpBuilder &builder, Attribute attr,
1175  IntType type, APInt &value) {
1176  auto &result = constantCache[{attr, type}];
1177  if (result)
1178  return result;
1179 
1180  // Make sure to insert constants at the top level of the module to maintain
1181  // dominance.
1182  OpBuilder::InsertPoint savedIP;
1183 
1184  auto *parentOp = builder.getInsertionBlock()->getParentOp();
1185  if (!isa<FModuleOp>(parentOp)) {
1186  savedIP = builder.saveInsertionPoint();
1187  while (!isa<FModuleOp>(parentOp)) {
1188  builder.setInsertionPoint(parentOp);
1189  parentOp = builder.getInsertionBlock()->getParentOp();
1190  }
1191  }
1192 
1193  result = builder.create<ConstantOp>(type, value);
1194 
1195  if (savedIP.isSet())
1196  builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1197 
1198  return result;
1199  }
1200 
1201  //===--------------------------------------------------------------------===//
1202  // SubaccessCache
1203 
1204  /// This returns a reference with the assumption that the caller will fill in
1205  /// the cached value. We keep track of inserted subaccesses so that we can
1206  /// remove them when we exit a scope.
1207  Value &getCachedSubaccess(Value value, unsigned index) {
1208  auto &result = subaccessCache[{value, index}];
1209  if (!result) {
1210  // The outer most block won't be in the map.
1211  auto it = scopeMap.find(value.getParentBlock());
1212  if (it != scopeMap.end())
1213  it->second->scopedSubaccesses.push_back({result, index});
1214  }
1215  return result;
1216  }
1217 
1218  //===--------------------------------------------------------------------===//
1219  // SymbolTable
1220 
1221  /// Add a symbol entry with the specified name, returning failure if the name
1222  /// is already defined.
1223  ParseResult addSymbolEntry(StringRef name, SymbolValueEntry entry, SMLoc loc,
1224  bool insertNameIntoGlobalScope = false);
1225  ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1226  bool insertNameIntoGlobalScope = false) {
1227  return addSymbolEntry(name, SymbolValueEntry(value), loc,
1228  insertNameIntoGlobalScope);
1229  }
1230 
1231  /// Resolved a symbol table entry to a value. Emission of error is optional.
1232  ParseResult resolveSymbolEntry(Value &result, SymbolValueEntry &entry,
1233  SMLoc loc, bool fatal = true);
1234 
1235  /// Resolved a symbol table entry if it is an expanded bundle e.g. from an
1236  /// instance. Emission of error is optional.
1237  ParseResult resolveSymbolEntry(Value &result, SymbolValueEntry &entry,
1238  StringRef field, SMLoc loc);
1239 
1240  /// Look up the specified name, emitting an error and returning failure if the
1241  /// name is unknown.
1242  ParseResult lookupSymbolEntry(SymbolValueEntry &result, StringRef name,
1243  SMLoc loc);
1244 
1245  UnbundledValueEntry &getUnbundledEntry(unsigned index) {
1246  assert(index < unbundledValues.size());
1247  return unbundledValues[index];
1248  }
1249 
1250  /// This contains one entry for each value in FIRRTL that is represented as a
1251  /// bundle type in the FIRRTL spec but for which we represent as an exploded
1252  /// set of elements in the FIRRTL dialect.
1253  UnbundledValuesList unbundledValues;
1254 
1255  /// Provide a symbol table scope that automatically pops all the entries off
1256  /// the symbol table when the scope is exited.
1257  struct ContextScope {
1258  friend struct FIRModuleContext;
1259  ContextScope(FIRModuleContext &moduleContext, Block *block)
1260  : moduleContext(moduleContext), block(block),
1261  previousScope(moduleContext.currentScope) {
1262  moduleContext.currentScope = this;
1263  moduleContext.scopeMap[block] = this;
1264  }
1265  ~ContextScope() {
1266  // Mark all entries in this scope as being invalid. We track validity
1267  // through the SMLoc field instead of deleting entries.
1268  for (auto *entryPtr : scopedDecls)
1269  entryPtr->second.first = SMLoc();
1270  // Erase the scoped subacceses from the cache. If the block is deleted we
1271  // could resuse the memory, although the chances are quite small.
1272  for (auto subaccess : scopedSubaccesses)
1273  moduleContext.subaccessCache.erase(subaccess);
1274  // Erase this context from the map.
1275  moduleContext.scopeMap.erase(block);
1276  // Reset to the previous scope.
1277  moduleContext.currentScope = previousScope;
1278  }
1279 
1280  private:
1281  void operator=(const ContextScope &) = delete;
1282  ContextScope(const ContextScope &) = delete;
1283 
1284  FIRModuleContext &moduleContext;
1285  Block *block;
1286  ContextScope *previousScope;
1287  std::vector<ModuleSymbolTableEntry *> scopedDecls;
1288  std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1289  };
1290 
1291 private:
1292  /// This symbol table holds the names of ports, wires, and other local decls.
1293  /// This is scoped because conditional statements introduce subscopes.
1294  ModuleSymbolTable symbolTable;
1295 
1296  /// This is a cache of subindex and subfield operations so we don't constantly
1297  /// recreate large chains of them. This maps a bundle value + index to the
1298  /// subaccess result.
1299  SubaccessCache subaccessCache;
1300 
1301  /// This maps a block to related ContextScope.
1302  DenseMap<Block *, ContextScope *> scopeMap;
1303 
1304  /// If non-null, all new entries added to the symbol table are added to this
1305  /// list. This allows us to "pop" the entries by resetting them to null when
1306  /// scope is exited.
1307  ContextScope *currentScope = nullptr;
1308 };
1309 
1310 } // end anonymous namespace
1311 
1312 /// Add a symbol entry with the specified name, returning failure if the name
1313 /// is already defined.
1314 ///
1315 /// When 'insertNameIntoGlobalScope' is true, we don't allow the name to be
1316 /// popped. This is a workaround for (firrtl scala bug) that should eventually
1317 /// be fixed.
1318 ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1319  SymbolValueEntry entry, SMLoc loc,
1320  bool insertNameIntoGlobalScope) {
1321  // Do a lookup by trying to do an insertion. Do so in a way that we can tell
1322  // if we hit a missing element (SMLoc is null).
1323  auto entryIt =
1324  symbolTable.try_emplace(name, SMLoc(), SymbolValueEntry()).first;
1325  if (entryIt->second.first.isValid()) {
1326  emitError(loc, "redefinition of name '" + name + "'")
1327  .attachNote(translateLocation(entryIt->second.first))
1328  << "previous definition here";
1329  return failure();
1330  }
1331 
1332  // If we didn't have a hit, then record the location, and remember that this
1333  // was new to this scope.
1334  entryIt->second = {loc, entry};
1335  if (currentScope && !insertNameIntoGlobalScope)
1336  currentScope->scopedDecls.push_back(&*entryIt);
1337 
1338  return success();
1339 }
1340 
1341 /// Look up the specified name, emitting an error and returning null if the
1342 /// name is unknown.
1343 ParseResult FIRModuleContext::lookupSymbolEntry(SymbolValueEntry &result,
1344  StringRef name, SMLoc loc) {
1345  auto &entry = symbolTable[name];
1346  if (!entry.first.isValid())
1347  return emitError(loc, "use of unknown declaration '" + name + "'");
1348  result = entry.second;
1349  assert(result && "name in symbol table without definition");
1350  return success();
1351 }
1352 
1353 ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1354  SymbolValueEntry &entry,
1355  SMLoc loc, bool fatal) {
1356  if (!entry.is<Value>()) {
1357  if (fatal)
1358  emitError(loc, "bundle value should only be used from subfield");
1359  return failure();
1360  }
1361  result = entry.get<Value>();
1362  return success();
1363 }
1364 
1365 ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1366  SymbolValueEntry &entry,
1367  StringRef fieldName,
1368  SMLoc loc) {
1369  if (!entry.is<UnbundledID>()) {
1370  emitError(loc, "value should not be used from subfield");
1371  return failure();
1372  }
1373 
1374  auto fieldAttr = StringAttr::get(getContext(), fieldName);
1375 
1376  unsigned unbundledId = entry.get<UnbundledID>() - 1;
1377  assert(unbundledId < unbundledValues.size());
1378  UnbundledValueEntry &ubEntry = unbundledValues[unbundledId];
1379  for (auto elt : ubEntry) {
1380  if (elt.first == fieldAttr) {
1381  result = elt.second;
1382  break;
1383  }
1384  }
1385  if (!result) {
1386  emitError(loc, "use of invalid field name '")
1387  << fieldName << "' on bundle value";
1388  return failure();
1389  }
1390 
1391  return success();
1392 }
1393 
1394 //===----------------------------------------------------------------------===//
1395 // FIRStmtParser
1396 //===----------------------------------------------------------------------===//
1397 
1398 namespace {
1399 /// This class is used when building expression nodes for a statement: we need
1400 /// to parse a bunch of expressions and build MLIR operations for them, and then
1401 /// we see the locator that specifies the location for those operations
1402 /// afterward.
1403 ///
1404 /// It is wasteful in time and memory to create a bunch of temporary FileLineCol
1405 /// location's that point into the .fir file when they're destined to get
1406 /// overwritten by a location specified by a Locator. To avoid this, we create
1407 /// all of the operations with a temporary location on them, then remember the
1408 /// [Operation*, SMLoc] pair for the newly created operation.
1409 ///
1410 /// At the end of the operation we'll see a Locator (or not). If we see a
1411 /// locator, we apply it to all the operations we've parsed and we're done. If
1412 /// not, we lazily create the locators in the .fir file.
1413 struct LazyLocationListener : public OpBuilder::Listener {
1414  LazyLocationListener(OpBuilder &builder) : builder(builder) {
1415  assert(builder.getListener() == nullptr);
1416  builder.setListener(this);
1417  }
1418 
1419  ~LazyLocationListener() {
1420  assert(subOps.empty() && "didn't process parsed operations");
1421  assert(builder.getListener() == this);
1422  builder.setListener(nullptr);
1423  }
1424 
1425  void startStatement() {
1426  assert(!isActive && "Already processing a statement");
1427  isActive = true;
1428  }
1429 
1430  /// This is called when done with each statement. This applies the locations
1431  /// to each statement.
1432  void endStatement(FIRParser &parser) {
1433  assert(isActive && "Not parsing a statement");
1434 
1435  // If we have a symbolic location, apply it to any subOps specified.
1436  if (infoLoc) {
1437  for (auto opAndSMLoc : subOps) {
1438  // Follow user preference to either only use @info locations,
1439  // or apply a fused location with @info and file loc.
1441  switch (parser.getConstants().options.infoLocatorHandling) {
1442  case ILH::IgnoreInfo:
1443  // Shouldn't have an infoLoc, but if we do ignore it.
1444  opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1445  break;
1446  case ILH::PreferInfo:
1447  opAndSMLoc.first->setLoc(infoLoc);
1448  break;
1449  case ILH::FusedInfo:
1450  opAndSMLoc.first->setLoc(FusedLoc::get(
1451  infoLoc.getContext(),
1452  {infoLoc, parser.translateLocation(opAndSMLoc.second)}));
1453  break;
1454  }
1455  }
1456  } else {
1457  // If we don't, translate all the individual SMLoc's to Location objects
1458  // in the .fir file.
1459  for (auto opAndSMLoc : subOps)
1460  opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1461  }
1462 
1463  // Reset our state.
1464  isActive = false;
1465  infoLoc = LocationAttr();
1466  currentSMLoc = SMLoc();
1467  subOps.clear();
1468  }
1469 
1470  /// Specify the location to be used for the next operations that are created.
1471  void setLoc(SMLoc loc) { currentSMLoc = loc; }
1472 
1473  /// When a @Info locator is parsed, this method captures it.
1474  void setInfoLoc(LocationAttr loc) {
1475  assert(!infoLoc && "Info location multiply specified");
1476  infoLoc = loc;
1477  }
1478 
1479  // Notification handler for when an operation is inserted into the builder.
1480  /// `op` is the operation that was inserted.
1481  void notifyOperationInserted(Operation *op) override {
1482  assert(currentSMLoc != SMLoc() && "No .fir file location specified");
1483  assert(isActive && "Not parsing a statement");
1484  subOps.push_back({op, currentSMLoc});
1485  }
1486 
1487 private:
1488  /// This is set to true while parsing a statement. It is used for assertions.
1489  bool isActive = false;
1490 
1491  /// This is the current position in the source file that the next operation
1492  /// will be parsed into.
1493  SMLoc currentSMLoc;
1494 
1495  /// This is the @ location attribute for the current statement, or null if
1496  /// not set.
1497  LocationAttr infoLoc;
1498 
1499  /// This is the builder we're installed into.
1500  OpBuilder &builder;
1501 
1502  /// This is the set of operations we've enqueued along with their location in
1503  /// the source file.
1504  SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1505 
1506  void operator=(const LazyLocationListener &) = delete;
1507  LazyLocationListener(const LazyLocationListener &) = delete;
1508 };
1509 } // end anonymous namespace
1510 
1511 namespace {
1512 /// This class implements logic and state for parsing statements, suites, and
1513 /// similar module body constructs.
1514 struct FIRStmtParser : public FIRParser {
1515  explicit FIRStmtParser(Block &blockToInsertInto,
1516  FIRModuleContext &moduleContext,
1517  hw::InnerSymbolNamespace &modNameSpace,
1518  FIRVersion version, SymbolRefAttr groupSym = {})
1519  : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1520  version),
1521  builder(UnknownLoc::get(getContext()), getContext()),
1522  locationProcessor(this->builder), moduleContext(moduleContext),
1523  modNameSpace(modNameSpace), groupSym(groupSym) {
1524  builder.setInsertionPointToEnd(&blockToInsertInto);
1525  }
1526 
1527  ParseResult parseSimpleStmt(unsigned stmtIndent);
1528  ParseResult parseSimpleStmtBlock(unsigned indent);
1529 
1530 private:
1531  ParseResult parseSimpleStmtImpl(unsigned stmtIndent);
1532 
1533  /// Attach invalid values to every element of the value.
1534  void emitInvalidate(Value val, Flow flow);
1535 
1536  // The FIRRTL specification describes Invalidates as a statement with
1537  // implicit connect semantics. The FIRRTL dialect models it as a primitive
1538  // that returns an "Invalid Value", followed by an explicit connect to make
1539  // the representation simpler and more consistent.
1540  void emitInvalidate(Value val) { emitInvalidate(val, foldFlow(val)); }
1541 
1542  /// Emit the logic for a partial connect using standard connect.
1543  void emitPartialConnect(ImplicitLocOpBuilder &builder, Value dst, Value src);
1544 
1545  /// Parse an @info marker if present and inform locationProcessor about it.
1546  ParseResult parseOptionalInfo() {
1547  LocationAttr loc;
1548  if (failed(parseOptionalInfoLocator(loc)))
1549  return failure();
1550  locationProcessor.setInfoLoc(loc);
1551  return success();
1552  }
1553 
1554  // Exp Parsing
1555  ParseResult parseExpImpl(Value &result, const Twine &message,
1556  bool isLeadingStmt);
1557  ParseResult parseExp(Value &result, const Twine &message) {
1558  return parseExpImpl(result, message, /*isLeadingStmt:*/ false);
1559  }
1560  ParseResult parseExpLeadingStmt(Value &result, const Twine &message) {
1561  return parseExpImpl(result, message, /*isLeadingStmt:*/ true);
1562  }
1563  ParseResult parseEnumExp(Value &result);
1564  ParseResult parsePathExp(Value &result);
1565  ParseResult parseRefExp(Value &result, const Twine &message);
1566  ParseResult parseStaticRefExp(Value &result, const Twine &message);
1567 
1568  template <typename subop>
1569  FailureOr<Value> emitCachedSubAccess(Value base,
1570  ArrayRef<NamedAttribute> attrs,
1571  unsigned indexNo, SMLoc loc);
1572  ParseResult parseOptionalExpPostscript(Value &result,
1573  bool allowDynamic = true);
1574  ParseResult parsePostFixFieldId(Value &result);
1575  ParseResult parsePostFixIntSubscript(Value &result);
1576  ParseResult parsePostFixDynamicSubscript(Value &result);
1577  ParseResult parsePrimExp(Value &result);
1578  ParseResult parseIntegerLiteralExp(Value &result);
1579  ParseResult parseListExp(Value &result);
1580  ParseResult parseMapExp(Value &result);
1581 
1582  std::optional<ParseResult> parseExpWithLeadingKeyword(FIRToken keyword);
1583 
1584  // Stmt Parsing
1585  ParseResult parseSubBlock(Block &blockToInsertInto, unsigned indent,
1586  SymbolRefAttr groupSym);
1587  ParseResult parseAttach();
1588  ParseResult parseMemPort(MemDirAttr direction);
1589  ParseResult parsePrintf();
1590  ParseResult parseSkip();
1591  ParseResult parseStop();
1592  ParseResult parseAssert();
1593  ParseResult parseAssume();
1594  ParseResult parseCover();
1595  ParseResult parseWhen(unsigned whenIndent);
1596  ParseResult parseMatch(unsigned matchIndent);
1597  ParseResult parseRefDefine();
1598  ParseResult parseRefForce();
1599  ParseResult parseRefForceInitial();
1600  ParseResult parseRefRelease();
1601  ParseResult parseRefReleaseInitial();
1602  ParseResult parseRefRead(Value &result);
1603  ParseResult parseProbe(Value &result);
1604  ParseResult parsePropAssign();
1605  ParseResult parseRWProbe(Value &result);
1606  ParseResult parseLeadingExpStmt(Value lhs);
1607  ParseResult parseConnect();
1608  ParseResult parseInvalidate();
1609  ParseResult parseGroup(unsigned indent);
1610 
1611  // Declarations
1612  ParseResult parseInstance();
1613  ParseResult parseObject();
1614  ParseResult parseCombMem();
1615  ParseResult parseSeqMem();
1616  ParseResult parseMem(unsigned memIndent);
1617  ParseResult parseNode();
1618  ParseResult parseWire();
1619  ParseResult parseRegister(unsigned regIndent);
1620  ParseResult parseRegisterWithReset();
1621 
1622  // The builder to build into.
1623  ImplicitLocOpBuilder builder;
1624  LazyLocationListener locationProcessor;
1625 
1626  // Extra information maintained across a module.
1627  FIRModuleContext &moduleContext;
1628 
1629  hw::InnerSymbolNamespace &modNameSpace;
1630 
1631  // An optional symbol that contains the current group that we are in. This is
1632  // used to construct a nested symbol for a group definition operation.
1633  SymbolRefAttr groupSym;
1634 };
1635 
1636 } // end anonymous namespace
1637 
1638 /// Attach invalid values to every element of the value.
1639 // NOLINTNEXTLINE(misc-no-recursion)
1640 void FIRStmtParser::emitInvalidate(Value val, Flow flow) {
1641  auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
1642  // Invalidate does nothing for non-base types.
1643  // When aggregates-of-refs are supported, instead check 'containsReference'
1644  // below.
1645  if (!tpe)
1646  return;
1647 
1648  auto props = tpe.getRecursiveTypeProperties();
1649  if (props.isPassive && !props.containsAnalog) {
1650  if (flow == Flow::Source)
1651  return;
1652  emitConnect(builder, val, builder.create<InvalidValueOp>(tpe));
1653  return;
1654  }
1655 
1656  // Recurse until we hit passive leaves. Connect any leaves which have sink or
1657  // duplex flow.
1658  //
1659  // TODO: This is very similar to connect expansion in the LowerTypes pass
1660  // works. Find a way to unify this with methods common to LowerTypes or to
1661  // have LowerTypes to the actual work here, e.g., emitting a partial connect
1662  // to only the leaf sources.
1663  TypeSwitch<FIRRTLType>(tpe)
1664  .Case<BundleType>([&](auto tpe) {
1665  for (size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
1666  auto &subfield = moduleContext.getCachedSubaccess(val, i);
1667  if (!subfield) {
1668  OpBuilder::InsertionGuard guard(builder);
1669  builder.setInsertionPointAfterValue(val);
1670  subfield = builder.create<SubfieldOp>(val, i);
1671  }
1672  emitInvalidate(subfield,
1673  tpe.getElement(i).isFlip ? swapFlow(flow) : flow);
1674  }
1675  })
1676  .Case<FVectorType>([&](auto tpe) {
1677  auto tpex = tpe.getElementType();
1678  for (size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
1679  auto &subindex = moduleContext.getCachedSubaccess(val, i);
1680  if (!subindex) {
1681  OpBuilder::InsertionGuard guard(builder);
1682  builder.setInsertionPointAfterValue(val);
1683  subindex = builder.create<SubindexOp>(tpex, val, i);
1684  }
1685  emitInvalidate(subindex, flow);
1686  }
1687  });
1688 }
1689 
1690 void FIRStmtParser::emitPartialConnect(ImplicitLocOpBuilder &builder, Value dst,
1691  Value src) {
1692  auto dstType = type_dyn_cast<FIRRTLBaseType>(dst.getType());
1693  auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
1694  if (!dstType || !srcType)
1695  return emitConnect(builder, dst, src);
1696 
1697  if (type_isa<AnalogType>(dstType)) {
1698  builder.create<AttachOp>(ArrayRef<Value>{dst, src});
1699  } else if (dstType == srcType && !dstType.containsAnalog()) {
1700  emitConnect(builder, dst, src);
1701  } else if (auto dstBundle = type_dyn_cast<BundleType>(dstType)) {
1702  auto srcBundle = type_cast<BundleType>(srcType);
1703  auto numElements = dstBundle.getNumElements();
1704  for (size_t dstIndex = 0; dstIndex < numElements; ++dstIndex) {
1705  // Find a matching field by name in the other bundle.
1706  auto &dstElement = dstBundle.getElements()[dstIndex];
1707  auto name = dstElement.name;
1708  auto maybe = srcBundle.getElementIndex(name);
1709  // If there was no matching field name, don't connect this one.
1710  if (!maybe)
1711  continue;
1712  auto dstRef = moduleContext.getCachedSubaccess(dst, dstIndex);
1713  if (!dstRef) {
1714  OpBuilder::InsertionGuard guard(builder);
1715  builder.setInsertionPointAfterValue(dst);
1716  dstRef = builder.create<SubfieldOp>(dst, dstIndex);
1717  }
1718  // We are pulling two fields from the cache. If the dstField was a
1719  // pointer into the cache, then the lookup for srcField might invalidate
1720  // it. So, we just copy dstField into a local.
1721  auto dstField = dstRef;
1722  auto srcIndex = *maybe;
1723  auto &srcField = moduleContext.getCachedSubaccess(src, srcIndex);
1724  if (!srcField) {
1725  OpBuilder::InsertionGuard guard(builder);
1726  builder.setInsertionPointAfterValue(src);
1727  srcField = builder.create<SubfieldOp>(src, srcIndex);
1728  }
1729  if (!dstElement.isFlip)
1730  emitPartialConnect(builder, dstField, srcField);
1731  else
1732  emitPartialConnect(builder, srcField, dstField);
1733  }
1734  } else if (auto dstVector = type_dyn_cast<FVectorType>(dstType)) {
1735  auto srcVector = type_cast<FVectorType>(srcType);
1736  auto dstNumElements = dstVector.getNumElements();
1737  auto srcNumEelemnts = srcVector.getNumElements();
1738  // Partial connect will connect all elements up to the end of the array.
1739  auto numElements = std::min(dstNumElements, srcNumEelemnts);
1740  for (size_t i = 0; i != numElements; ++i) {
1741  auto &dstRef = moduleContext.getCachedSubaccess(dst, i);
1742  if (!dstRef) {
1743  OpBuilder::InsertionGuard guard(builder);
1744  builder.setInsertionPointAfterValue(dst);
1745  dstRef = builder.create<SubindexOp>(dst, i);
1746  }
1747  auto dstField = dstRef; // copy to ensure not invalidated
1748  auto &srcField = moduleContext.getCachedSubaccess(src, i);
1749  if (!srcField) {
1750  OpBuilder::InsertionGuard guard(builder);
1751  builder.setInsertionPointAfterValue(src);
1752  srcField = builder.create<SubindexOp>(src, i);
1753  }
1754  emitPartialConnect(builder, dstField, srcField);
1755  }
1756  } else {
1757  emitConnect(builder, dst, src);
1758  }
1759 }
1760 
1761 //===-------------------------------
1762 // FIRStmtParser Expression Parsing.
1763 
1764 /// Parse the 'exp' grammar, returning all of the suboperations in the
1765 /// specified vector, and the ultimate SSA value in value.
1766 ///
1767 /// exp ::= id // Ref
1768 /// ::= prim
1769 /// ::= integer-literal-exp
1770 /// ::= enum-exp
1771 /// ::= list-exp
1772 /// ::= 'String(' stringLit ')'
1773 /// ::= exp '.' fieldId
1774 /// ::= exp '[' intLit ']'
1775 /// XX ::= exp '.' DoubleLit // TODO Workaround for #470
1776 /// ::= exp '[' exp ']'
1777 ///
1778 ///
1779 /// If 'isLeadingStmt' is true, then this is being called to parse the first
1780 /// expression in a statement. We can handle some weird cases due to this if
1781 /// we end up parsing the whole statement. In that case we return success, but
1782 /// set the 'result' value to null.
1783 // NOLINTNEXTLINE(misc-no-recursion)
1784 ParseResult FIRStmtParser::parseExpImpl(Value &result, const Twine &message,
1785  bool isLeadingStmt) {
1786  switch (getToken().getKind()) {
1787 
1788  // Handle all primitive's.
1789 #define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS) \
1790  case FIRToken::lp_##SPELLING:
1791 #include "FIRTokenKinds.def"
1792  if (parsePrimExp(result))
1793  return failure();
1794  break;
1795 
1796  case FIRToken::l_brace_bar:
1797  if (isLeadingStmt)
1798  return emitError("unexpected enumeration as start of statement");
1799  if (parseEnumExp(result))
1800  return failure();
1801  break;
1802  case FIRToken::lp_read:
1803  if (isLeadingStmt)
1804  return emitError("unexpected read() as start of statement");
1805  if (parseRefRead(result))
1806  return failure();
1807  break;
1808  case FIRToken::lp_probe:
1809  if (isLeadingStmt)
1810  return emitError("unexpected probe() as start of statement");
1811  if (parseProbe(result))
1812  return failure();
1813  break;
1814  case FIRToken::lp_rwprobe:
1815  if (isLeadingStmt)
1816  return emitError("unexpected rwprobe() as start of statement");
1817  if (parseRWProbe(result))
1818  return failure();
1819  break;
1820 
1821  case FIRToken::kw_UInt:
1822  case FIRToken::kw_SInt:
1823  if (parseIntegerLiteralExp(result))
1824  return failure();
1825  break;
1826  case FIRToken::kw_String: {
1827  if (requireFeature({3, 1, 0}, "Strings"))
1828  return failure();
1829  locationProcessor.setLoc(getToken().getLoc());
1830  consumeToken(FIRToken::kw_String);
1831  StringRef spelling;
1832  if (parseToken(FIRToken::l_paren, "expected '(' in String expression") ||
1833  parseGetSpelling(spelling) ||
1834  parseToken(FIRToken::string,
1835  "expected string literal in String expression") ||
1836  parseToken(FIRToken::r_paren, "expected ')' in String expression"))
1837  return failure();
1838  result = builder.create<StringConstantOp>(
1839  builder.getStringAttr(FIRToken::getStringValue(spelling)));
1840  break;
1841  }
1842  case FIRToken::kw_Integer: {
1843  if (requireFeature({3, 1, 0}, "Integers"))
1844  return failure();
1845  locationProcessor.setLoc(getToken().getLoc());
1846  consumeToken(FIRToken::kw_Integer);
1847  APInt value;
1848  if (parseToken(FIRToken::l_paren, "expected '(' in Integer expression") ||
1849  parseIntLit(value, "expected integer literal in Integer expression") ||
1850  parseToken(FIRToken::r_paren, "expected ')' in Integer expression"))
1851  return failure();
1852  result =
1853  builder.create<FIntegerConstantOp>(APSInt(value, /*isUnsigned=*/false));
1854  break;
1855  }
1856  case FIRToken::kw_Bool: {
1857  if (requireFeature({3, 2, 0}, "Bools"))
1858  return failure();
1859  locationProcessor.setLoc(getToken().getLoc());
1860  consumeToken(FIRToken::kw_Bool);
1861  if (parseToken(FIRToken::l_paren, "expected '(' in Bool expression"))
1862  return failure();
1863  bool value;
1864  if (consumeIf(FIRToken::kw_true))
1865  value = true;
1866  else if (consumeIf(FIRToken::kw_false))
1867  value = false;
1868  else
1869  return emitError("expected true or false in Bool expression");
1870  if (parseToken(FIRToken::r_paren, "expected ')' in Bool expression"))
1871  return failure();
1872  result = builder.create<BoolConstantOp>(value);
1873  break;
1874  }
1875  case FIRToken::kw_Double: {
1876  if (requireFeature({3, 2, 0}, "Doubles"))
1877  return failure();
1878  locationProcessor.setLoc(getToken().getLoc());
1879  consumeToken(FIRToken::kw_Double);
1880  if (parseToken(FIRToken::l_paren, "expected '(' in Double expression"))
1881  return failure();
1882  auto spelling = getTokenSpelling();
1883  if (parseToken(FIRToken::floatingpoint,
1884  "expected floating point in Double expression") ||
1885  parseToken(FIRToken::r_paren, "expected ')' in Double expression"))
1886  return failure();
1887  // NaN, INF, exponent, hex, integer?
1888  // This uses `strtod` internally, FWIW. See `man 3 strtod`.
1889  double d;
1890  if (!llvm::to_float(spelling, d))
1891  return emitError("invalid double");
1892  result = builder.create<DoubleConstantOp>(builder.getF64FloatAttr(d));
1893  break;
1894  }
1895  case FIRToken::kw_List: {
1896  if (requireFeature({3, 2, 0}, "Lists"))
1897  return failure();
1898  if (isLeadingStmt)
1899  return emitError("unexpected List<>() as start of statement");
1900  if (parseListExp(result))
1901  return failure();
1902  break;
1903  }
1904  case FIRToken::kw_Map: {
1905  if (requireFeature({3, 2, 0}, "Maps"))
1906  return failure();
1907  if (isLeadingStmt)
1908  return emitError("unexpected Map<>() as start of statement");
1909  if (parseMapExp(result))
1910  return failure();
1911  break;
1912  }
1913  case FIRToken::lp_path:
1914  if (isLeadingStmt)
1915  return emitError("unexpected path() as start of statement");
1916  if (requireFeature({3, 2, 0}, "paths") || parsePathExp(result))
1917  return failure();
1918  break;
1919 
1920  // Otherwise there are a bunch of keywords that are treated as identifiers
1921  // try them.
1922  case FIRToken::identifier: // exp ::= id
1923  case FIRToken::literal_identifier:
1924  default: {
1925  StringRef name;
1926  auto loc = getToken().getLoc();
1927  SymbolValueEntry symtabEntry;
1928  if (parseId(name, message) ||
1929  moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
1930  return failure();
1931 
1932  // If we looked up a normal value, then we're done.
1933  if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc, false))
1934  break;
1935 
1936  assert(symtabEntry.is<UnbundledID>() && "should be an instance");
1937 
1938  // Otherwise we referred to an implicitly bundled value. We *must* be in
1939  // the midst of processing a field ID reference or 'is invalid'. If not,
1940  // this is an error.
1941  if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
1942  if (parseToken(FIRToken::kw_invalid, "expected 'invalid'") ||
1943  parseOptionalInfo())
1944  return failure();
1945 
1946  locationProcessor.setLoc(loc);
1947  // Invalidate all of the results of the bundled value.
1948  unsigned unbundledId = symtabEntry.get<UnbundledID>() - 1;
1949  UnbundledValueEntry &ubEntry =
1950  moduleContext.getUnbundledEntry(unbundledId);
1951  for (auto elt : ubEntry)
1952  emitInvalidate(elt.second);
1953 
1954  // Signify that we parsed the whole statement.
1955  result = Value();
1956  return success();
1957  }
1958 
1959  // Handle the normal "instance.x" reference.
1960  StringRef fieldName;
1961  if (parseToken(FIRToken::period, "expected '.' in field reference") ||
1962  parseFieldId(fieldName, "expected field name") ||
1963  moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
1964  return failure();
1965  break;
1966  }
1967  }
1968 
1969  return parseOptionalExpPostscript(result);
1970 }
1971 
1972 /// Parse the postfix productions of expression after the leading expression
1973 /// has been parsed.
1974 ///
1975 /// exp ::= exp '.' fieldId
1976 /// ::= exp '[' intLit ']'
1977 /// XX ::= exp '.' DoubleLit // TODO Workaround for #470
1978 /// ::= exp '[' exp ']'
1979 ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
1980  bool allowDynamic) {
1981 
1982  // Handle postfix expressions.
1983  while (true) {
1984  // Subfield: exp ::= exp '.' fieldId
1985  if (consumeIf(FIRToken::period)) {
1986  if (parsePostFixFieldId(result))
1987  return failure();
1988 
1989  continue;
1990  }
1991 
1992  // Subindex: exp ::= exp '[' intLit ']' | exp '[' exp ']'
1993  if (consumeIf(FIRToken::l_square)) {
1994  if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
1995  if (parsePostFixIntSubscript(result))
1996  return failure();
1997  continue;
1998  }
1999  if (!allowDynamic)
2000  return emitError("subaccess not allowed here");
2001  if (parsePostFixDynamicSubscript(result))
2002  return failure();
2003 
2004  continue;
2005  }
2006 
2007  return success();
2008  }
2009 }
2010 
2011 template <typename subop>
2013 FIRStmtParser::emitCachedSubAccess(Value base, ArrayRef<NamedAttribute> attrs,
2014  unsigned indexNo, SMLoc loc) {
2015  // Make sure the field name matches up with the input value's type and
2016  // compute the result type for the expression.
2017  auto resultType = subop::inferReturnType({base}, attrs, {});
2018  if (!resultType) {
2019  // Emit the error at the right location. translateLocation is expensive.
2020  (void)subop::inferReturnType({base}, attrs, translateLocation(loc));
2021  return failure();
2022  }
2023 
2024  // Check if we already have created this Subindex op.
2025  auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2026  if (value)
2027  return value;
2028 
2029  // Create the result operation, inserting at the location of the declaration.
2030  // This will cache the subfield operation for further uses.
2031  locationProcessor.setLoc(loc);
2032  OpBuilder::InsertionGuard guard(builder);
2033  builder.setInsertionPointAfterValue(base);
2034  auto op = builder.create<subop>(resultType, base, attrs);
2035 
2036  // Insert the newly created operation into the cache.
2037  return value = op.getResult();
2038 }
2039 
2040 /// exp ::= exp '.' fieldId
2041 ///
2042 /// The "exp '.'" part of the production has already been parsed.
2043 ///
2044 ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2045  auto loc = getToken().getLoc();
2046  SmallVector<StringRef, 3> fields;
2047  if (parseFieldIdSeq(fields, "expected field name"))
2048  return failure();
2049  for (auto fieldName : fields) {
2050  std::optional<unsigned> indexV;
2051  auto type = result.getType();
2052  if (auto refTy = type_dyn_cast<RefType>(type))
2053  type = refTy.getType();
2054  if (auto bundle = type_dyn_cast<BundleType>(type))
2055  indexV = bundle.getElementIndex(fieldName);
2056  else if (auto bundle = type_dyn_cast<OpenBundleType>(type))
2057  indexV = bundle.getElementIndex(fieldName);
2058  else if (auto klass = type_dyn_cast<ClassType>(type))
2059  indexV = klass.getElementIndex(fieldName);
2060  else
2061  return emitError(loc, "subfield requires bundle or object operand ");
2062  if (!indexV)
2063  return emitError(loc, "unknown field '" + fieldName + "' in type ")
2064  << result.getType();
2065  auto indexNo = *indexV;
2066 
2067  FailureOr<Value> subResult;
2068  if (type_isa<RefType>(result.getType())) {
2069  NamedAttribute attrs = {getConstants().indexIdentifier,
2070  builder.getI32IntegerAttr(indexNo)};
2071  subResult = emitCachedSubAccess<RefSubOp>(result, attrs, indexNo, loc);
2072  } else if (type_isa<ClassType>(type)) {
2073  NamedAttribute attrs = {getConstants().indexIdentifier,
2074  builder.getI32IntegerAttr(indexNo)};
2075  subResult =
2076  emitCachedSubAccess<ObjectSubfieldOp>(result, attrs, indexNo, loc);
2077  } else {
2078  NamedAttribute attrs = {getConstants().fieldIndexIdentifier,
2079  builder.getI32IntegerAttr(indexNo)};
2080  if (type_isa<BundleType>(type))
2081  subResult =
2082  emitCachedSubAccess<SubfieldOp>(result, attrs, indexNo, loc);
2083  else
2084  subResult =
2085  emitCachedSubAccess<OpenSubfieldOp>(result, attrs, indexNo, loc);
2086  }
2087 
2088  if (failed(subResult))
2089  return failure();
2090  result = *subResult;
2091  }
2092  return success();
2093 }
2094 
2095 /// exp ::= exp '[' intLit ']'
2096 ///
2097 /// The "exp '['" part of the production has already been parsed.
2098 ///
2099 ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2100  auto loc = getToken().getLoc();
2101  int32_t indexNo;
2102  if (parseIntLit(indexNo, "expected index") ||
2103  parseToken(FIRToken::r_square, "expected ']'"))
2104  return failure();
2105 
2106  if (indexNo < 0)
2107  return emitError(loc, "invalid index specifier"), failure();
2108 
2109  // Make sure the index expression is valid and compute the result type for the
2110  // expression.
2111  // TODO: This should ideally be folded into a `tryCreate` method on the
2112  // builder (https://llvm.discourse.group/t/3504).
2113  NamedAttribute attrs = {getConstants().indexIdentifier,
2114  builder.getI32IntegerAttr(indexNo)};
2115 
2116  FailureOr<Value> subResult;
2117  if (type_isa<RefType>(result.getType()))
2118  subResult = emitCachedSubAccess<RefSubOp>(result, attrs, indexNo, loc);
2119  else if (type_isa<FVectorType>(result.getType()))
2120  subResult = emitCachedSubAccess<SubindexOp>(result, attrs, indexNo, loc);
2121  else
2122  subResult =
2123  emitCachedSubAccess<OpenSubindexOp>(result, attrs, indexNo, loc);
2124 
2125  if (failed(subResult))
2126  return failure();
2127  result = *subResult;
2128  return success();
2129 }
2130 
2131 /// exp ::= exp '[' exp ']'
2132 ///
2133 /// The "exp '['" part of the production has already been parsed.
2134 ///
2135 ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2136  auto loc = getToken().getLoc();
2137  Value index;
2138  if (parseExp(index, "expected subscript index expression") ||
2139  parseToken(FIRToken::r_square, "expected ']' in subscript"))
2140  return failure();
2141 
2142  // If the index expression is a flip type, strip it off.
2143  auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2144  if (!indexType)
2145  return emitError("expected base type for index expression");
2146  indexType = indexType.getPassiveType();
2147  locationProcessor.setLoc(loc);
2148 
2149  // Make sure the index expression is valid and compute the result type for the
2150  // expression.
2151  auto resultType = SubaccessOp::inferReturnType({result, index}, {}, {});
2152  if (!resultType) {
2153  // Emit the error at the right location. translateLocation is expensive.
2154  (void)SubaccessOp::inferReturnType({result, index}, {},
2155  translateLocation(loc));
2156  return failure();
2157  }
2158 
2159  // Create the result operation.
2160  auto op = builder.create<SubaccessOp>(resultType, result, index);
2161  result = op.getResult();
2162  return success();
2163 }
2164 
2165 /// prim ::= primop exp* intLit* ')'
2166 ParseResult FIRStmtParser::parsePrimExp(Value &result) {
2167  auto kind = getToken().getKind();
2168  auto loc = getToken().getLoc();
2169  consumeToken();
2170 
2171  // Parse the operands and constant integer arguments.
2172  SmallVector<Value, 3> operands;
2173  SmallVector<int64_t, 3> integers;
2174  if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2175  // Handle the integer constant case if present.
2176  if (getToken().isAny(FIRToken::integer, FIRToken::signed_integer,
2177  FIRToken::string)) {
2178  integers.push_back(0);
2179  return parseIntLit(integers.back(), "expected integer");
2180  }
2181 
2182  // Otherwise it must be a value operand. These must all come before the
2183  // integers.
2184  if (!integers.empty())
2185  return emitError("expected more integer constants"), failure();
2186 
2187  Value operand;
2188  if (parseExp(operand, "expected expression in primitive operand"))
2189  return failure();
2190 
2191  locationProcessor.setLoc(loc);
2192 
2193  operands.push_back(operand);
2194  return success();
2195  }))
2196  return failure();
2197 
2198  locationProcessor.setLoc(loc);
2199 
2200  SmallVector<FIRRTLType, 3> opTypes;
2201  for (auto v : operands)
2202  opTypes.push_back(type_cast<FIRRTLType>(v.getType()));
2203 
2204  unsigned numOperandsExpected;
2205  SmallVector<StringAttr, 2> attrNames;
2206 
2207  // Get information about the primitive in question.
2208  switch (kind) {
2209  default:
2210  emitError(loc, "primitive not supported yet");
2211  return failure();
2212 #define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS) \
2213  case FIRToken::lp_##SPELLING: \
2214  numOperandsExpected = NUMOPERANDS; \
2215  break;
2216 #include "FIRTokenKinds.def"
2217  }
2218  // Don't add code here, we want these two switch statements to be fused by
2219  // the compiler.
2220  switch (kind) {
2221  default:
2222  break;
2223  case FIRToken::lp_bits:
2224  attrNames.push_back(getConstants().hiIdentifier); // "hi"
2225  attrNames.push_back(getConstants().loIdentifier); // "lo"
2226  break;
2227  case FIRToken::lp_head:
2228  case FIRToken::lp_pad:
2229  case FIRToken::lp_shl:
2230  case FIRToken::lp_shr:
2231  case FIRToken::lp_tail:
2232  attrNames.push_back(getConstants().amountIdentifier);
2233  break;
2234  }
2235 
2236  if (operands.size() != numOperandsExpected) {
2237  assert(numOperandsExpected <= 3);
2238  static const char *numberName[] = {"zero", "one", "two", "three"};
2239  const char *optionalS = &"s"[numOperandsExpected == 1];
2240  return emitError(loc, "operation requires ")
2241  << numberName[numOperandsExpected] << " operand" << optionalS;
2242  }
2243 
2244  if (integers.size() != attrNames.size()) {
2245  emitError(loc, "expected ") << attrNames.size() << " constant arguments";
2246  return failure();
2247  }
2248 
2249  NamedAttrList attrs;
2250  for (size_t i = 0, e = attrNames.size(); i != e; ++i)
2251  attrs.append(attrNames[i], builder.getI32IntegerAttr(integers[i]));
2252 
2253  switch (kind) {
2254  default:
2255  emitError(loc, "primitive not supported yet");
2256  return failure();
2257 
2258 #define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS) \
2259  case FIRToken::lp_##SPELLING: { \
2260  auto resultTy = CLASS::inferReturnType(operands, attrs, {}); \
2261  if (!resultTy) { \
2262  /* only call translateLocation on an error case, it is expensive. */ \
2263  (void)CLASS::validateAndInferReturnType(operands, attrs, \
2264  translateLocation(loc)); \
2265  return failure(); \
2266  } \
2267  result = builder.create<CLASS>(resultTy, operands, attrs); \
2268  return success(); \
2269  }
2270 #include "FIRTokenKinds.def"
2271  }
2272 
2273  llvm_unreachable("all cases should return");
2274 }
2275 
2276 /// integer-literal-exp ::= 'UInt' optional-width '(' intLit ')'
2277 /// ::= 'SInt' optional-width '(' intLit ')'
2278 ParseResult FIRStmtParser::parseIntegerLiteralExp(Value &result) {
2279  bool isSigned = getToken().is(FIRToken::kw_SInt);
2280  auto loc = getToken().getLoc();
2281  consumeToken();
2282 
2283  // Parse a width specifier if present.
2284  int32_t width;
2285  APInt value;
2286  if (parseOptionalWidth(width) ||
2287  parseToken(FIRToken::l_paren, "expected '(' in integer expression") ||
2288  parseIntLit(value, "expected integer value") ||
2289  parseToken(FIRToken::r_paren, "expected ')' in integer expression"))
2290  return failure();
2291 
2292  // Construct an integer attribute of the right width.
2293  // Literals are parsed as 'const' types.
2294  auto type = IntType::get(builder.getContext(), isSigned, width, true);
2295 
2296  IntegerType::SignednessSemantics signedness =
2297  isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2298  if (width == 0) {
2299  if (!value.isZero())
2300  return emitError(loc, "zero bit constant must be zero");
2301  value = value.trunc(0);
2302  } else if (width != -1) {
2303  // Convert to the type's width, checking value fits in destination width.
2304  bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2305  if (!valueFits)
2306  return emitError(loc, "initializer too wide for declared width");
2307  value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2308  }
2309 
2310  Type attrType =
2311  IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2312  auto attr = builder.getIntegerAttr(attrType, value);
2313 
2314  // Check to see if we've already created this constant. If so, reuse it.
2315  auto &entry = moduleContext.constantCache[{attr, type}];
2316  if (entry) {
2317  // If we already had an entry, reuse it.
2318  result = entry;
2319  return success();
2320  }
2321 
2322  locationProcessor.setLoc(loc);
2323  result = moduleContext.getCachedConstantInt(builder, attr, type, value);
2324  return success();
2325 }
2326 
2327 /// list-exp ::= list-type '(' exp* ')'
2328 ParseResult FIRStmtParser::parseListExp(Value &result) {
2329  auto loc = getToken().getLoc();
2330  FIRRTLType type;
2331  if (parseListType(type))
2332  return failure();
2333  auto listType = type_cast<ListType>(type);
2334  auto elementType = listType.getElementType();
2335 
2336  if (parseToken(FIRToken::l_paren, "expected '(' in List expression"))
2337  return failure();
2338 
2339  SmallVector<Value, 3> operands;
2340  if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2341  Value operand;
2342  locationProcessor.setLoc(loc);
2343  if (parseExp(operand, "expected expression in List expression"))
2344  return failure();
2345 
2346  if (operand.getType() != elementType) {
2347  if (!isa<AnyRefType>(elementType) ||
2348  !isa<ClassType>(operand.getType()))
2349  return emitError(loc, "unexpected expression of type ")
2350  << operand.getType() << " in List expression of type "
2351  << elementType;
2352  operand = builder.create<ObjectAnyRefCastOp>(operand);
2353  }
2354 
2355  operands.push_back(operand);
2356  return success();
2357  }))
2358  return failure();
2359 
2360  locationProcessor.setLoc(loc);
2361  result = builder.create<ListCreateOp>(listType, operands);
2362  return success();
2363 }
2364 
2365 /// kv-pair ::= exp '->' exp
2366 /// map-exp ::= map-type '(' ( kv-pair ( ',' kv-pair )* )? ')'
2367 ParseResult FIRStmtParser::parseMapExp(Value &result) {
2368  auto loc = getToken().getLoc();
2369  FIRRTLType type;
2370  if (parseMapType(type))
2371  return failure();
2372  auto mapType = type_cast<MapType>(type);
2373  auto keyType = mapType.getKeyType();
2374  auto valueType = mapType.getValueType();
2375 
2376  if (parseToken(FIRToken::l_paren, "expected '(' in Map expression"))
2377  return failure();
2378 
2379  SmallVector<Value, 3> keys, values;
2380  if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2381  Value key, value;
2382  locationProcessor.setLoc(loc);
2383  if (parseExp(key, "expected key expression in Map expression") ||
2384  parseToken(FIRToken::minus_greater,
2385  "expected '->' in Map expression") ||
2386  parseExp(value, "expected value expression in Map expression"))
2387  return failure();
2388 
2389  if (key.getType() != keyType) {
2390  if (!isa<AnyRefType>(keyType) || !isa<ClassType>(key.getType()))
2391  return emitError(loc, "unexpected expression of type ")
2392  << key.getType() << " for key in Map expression, expected "
2393  << keyType;
2394  key = builder.create<ObjectAnyRefCastOp>(key);
2395  }
2396  if (value.getType() != valueType) {
2397  if (!isa<AnyRefType>(valueType) || !isa<ClassType>(value.getType()))
2398  return emitError(loc, "unexpected expression of type ")
2399  << value.getType()
2400  << " for value in Map expression, expected " << valueType;
2401  value = builder.create<ObjectAnyRefCastOp>(value);
2402  }
2403 
2404  keys.push_back(key);
2405  values.push_back(value);
2406  return success();
2407  }))
2408  return failure();
2409 
2410  locationProcessor.setLoc(loc);
2411  result = builder.create<MapCreateOp>(mapType, keys, values);
2412  return success();
2413 }
2414 
2415 /// The .fir grammar has the annoying property where:
2416 /// 1) some statements start with keywords
2417 /// 2) some start with an expression
2418 /// 3) it allows the 'reference' expression to either be an identifier or a
2419 /// keyword.
2420 ///
2421 /// One example of this is something like, where this is not a register decl:
2422 /// reg <- thing
2423 ///
2424 /// Solving this requires lookahead to the second token. We handle it by
2425 /// factoring the lookahead inline into the code to keep the parser fast.
2426 ///
2427 /// As such, statements that start with a leading keyword call this method to
2428 /// check to see if the keyword they consumed was actually the start of an
2429 /// expression. If so, they parse the expression-based statement and return the
2430 /// parser result. If not, they return None and the statement is parsed like
2431 /// normal.
2432 std::optional<ParseResult>
2433 FIRStmtParser::parseExpWithLeadingKeyword(FIRToken keyword) {
2434  switch (getToken().getKind()) {
2435  default:
2436  // This isn't part of an expression, and isn't part of a statement.
2437  return std::nullopt;
2438 
2439  case FIRToken::period: // exp `.` identifier
2440  case FIRToken::l_square: // exp `[` index `]`
2441  case FIRToken::kw_is: // exp is invalid
2442  case FIRToken::less_equal: // exp <= thing
2443  case FIRToken::less_minus: // exp <- thing
2444  break;
2445  }
2446 
2447  Value lhs;
2448  SymbolValueEntry symtabEntry;
2449  auto loc = keyword.getLoc();
2450 
2451  if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.getSpelling(), loc))
2452  return ParseResult(failure());
2453 
2454  // If we have a '.', we might have a symbol or an expanded port. If we
2455  // resolve to a symbol, use that, otherwise check for expanded bundles of
2456  // other ops.
2457  // Non '.' ops take the plain symbol path.
2458  if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc, false)) {
2459  // Ok if the base name didn't resolve by itself, it might be part of an
2460  // expanded dot reference. That doesn't work then we fail.
2461  if (!consumeIf(FIRToken::period))
2462  return ParseResult(failure());
2463 
2464  StringRef fieldName;
2465  if (parseFieldId(fieldName, "expected field name") ||
2466  moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2467  return ParseResult(failure());
2468  }
2469 
2470  // Parse any further trailing things like "mem.x.y".
2471  if (parseOptionalExpPostscript(lhs))
2472  return ParseResult(failure());
2473 
2474  return parseLeadingExpStmt(lhs);
2475 }
2476 //===-----------------------------
2477 // FIRStmtParser Statement Parsing
2478 
2479 /// simple_stmt_block ::= simple_stmt*
2480 ParseResult FIRStmtParser::parseSimpleStmtBlock(unsigned indent) {
2481  while (true) {
2482  // The outer level parser can handle these tokens.
2483  if (getToken().isAny(FIRToken::eof, FIRToken::error))
2484  return success();
2485 
2486  auto subIndent = getIndentation();
2487  if (!subIndent.has_value())
2488  return emitError("expected statement to be on its own line"), failure();
2489 
2490  if (*subIndent <= indent)
2491  return success();
2492 
2493  // Let the statement parser handle this.
2494  if (parseSimpleStmt(*subIndent))
2495  return failure();
2496  }
2497 }
2498 
2499 ParseResult FIRStmtParser::parseSimpleStmt(unsigned stmtIndent) {
2500  locationProcessor.startStatement();
2501  auto result = parseSimpleStmtImpl(stmtIndent);
2502  locationProcessor.endStatement(*this);
2503  return result;
2504 }
2505 
2506 /// simple_stmt ::= stmt
2507 ///
2508 /// stmt ::= attach
2509 /// ::= memport
2510 /// ::= printf
2511 /// ::= skip
2512 /// ::= stop
2513 /// ::= when
2514 /// ::= leading-exp-stmt
2515 /// ::= define
2516 /// ::= propassign
2517 ///
2518 /// stmt ::= instance
2519 /// ::= cmem | smem | mem
2520 /// ::= node | wire
2521 /// ::= register
2522 ///
2523 ParseResult FIRStmtParser::parseSimpleStmtImpl(unsigned stmtIndent) {
2524  auto kind = getToken().getKind();
2525  /// Massage the kind based on the FIRRTL Version.
2526  switch (kind) {
2527  case FIRToken::kw_invalidate:
2528  case FIRToken::kw_connect:
2529  case FIRToken::kw_regreset:
2530  /// The "invalidate", "connect", and "regreset" keywords were added
2531  /// in 3.0.0.
2532  if (version < FIRVersion(3, 0, 0))
2533  kind = FIRToken::identifier;
2534  break;
2535  default:
2536  break;
2537  };
2538  switch (kind) {
2539  // Statements.
2540  case FIRToken::kw_attach:
2541  return parseAttach();
2542  case FIRToken::kw_infer:
2543  return parseMemPort(MemDirAttr::Infer);
2544  case FIRToken::kw_read:
2545  return parseMemPort(MemDirAttr::Read);
2546  case FIRToken::kw_write:
2547  return parseMemPort(MemDirAttr::Write);
2548  case FIRToken::kw_rdwr:
2549  return parseMemPort(MemDirAttr::ReadWrite);
2550  case FIRToken::kw_connect:
2551  return parseConnect();
2552  case FIRToken::kw_propassign:
2553  if (requireFeature({3, 1, 0}, "properties"))
2554  return failure();
2555  return parsePropAssign();
2556  case FIRToken::kw_invalidate:
2557  return parseInvalidate();
2558  case FIRToken::lp_printf:
2559  return parsePrintf();
2560  case FIRToken::kw_skip:
2561  return parseSkip();
2562  case FIRToken::lp_stop:
2563  return parseStop();
2564  case FIRToken::lp_assert:
2565  return parseAssert();
2566  case FIRToken::lp_assume:
2567  return parseAssume();
2568  case FIRToken::lp_cover:
2569  return parseCover();
2570  case FIRToken::kw_when:
2571  return parseWhen(stmtIndent);
2572  case FIRToken::kw_match:
2573  return parseMatch(stmtIndent);
2574  case FIRToken::kw_define:
2575  return parseRefDefine();
2576  case FIRToken::lp_force:
2577  return parseRefForce();
2578  case FIRToken::lp_force_initial:
2579  return parseRefForceInitial();
2580  case FIRToken::lp_release:
2581  return parseRefRelease();
2582  case FIRToken::lp_release_initial:
2583  return parseRefReleaseInitial();
2584  case FIRToken::kw_group:
2585  if (requireFeature({3, 1, 0}, "optional groups"))
2586  return failure();
2587  return parseGroup(stmtIndent);
2588 
2589  default: {
2590  // Statement productions that start with an expression.
2591  Value lhs;
2592  if (parseExpLeadingStmt(lhs, "unexpected token in module"))
2593  return failure();
2594  // We use parseExp in a special mode that can complete the entire stmt at
2595  // once in unusual cases. If this happened, then we are done.
2596  if (!lhs)
2597  return success();
2598 
2599  return parseLeadingExpStmt(lhs);
2600  }
2601 
2602  // Declarations
2603  case FIRToken::kw_inst:
2604  return parseInstance();
2605  case FIRToken::kw_object:
2606  return parseObject();
2607  case FIRToken::kw_cmem:
2608  return parseCombMem();
2609  case FIRToken::kw_smem:
2610  return parseSeqMem();
2611  case FIRToken::kw_mem:
2612  return parseMem(stmtIndent);
2613  case FIRToken::kw_node:
2614  return parseNode();
2615  case FIRToken::kw_wire:
2616  return parseWire();
2617  case FIRToken::kw_reg:
2618  return parseRegister(stmtIndent);
2619  case FIRToken::kw_regreset:
2620  return parseRegisterWithReset();
2621  }
2622 }
2623 
2624 ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
2625  unsigned indent,
2626  SymbolRefAttr groupSym) {
2627  // Declarations within the suite are scoped to within the suite.
2628  auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
2629  moduleContext, &blockToInsertInto);
2630 
2631  // After parsing the when region, we can release any new entries in
2632  // unbundledValues since the symbol table entries that refer to them will be
2633  // gone.
2634  UnbundledValueRestorer x(moduleContext.unbundledValues);
2635 
2636  // We parse the substatements into their own parser, so they get inserted
2637  // into the specified 'when' region.
2638  auto subParser = std::make_unique<FIRStmtParser>(
2639  blockToInsertInto, moduleContext, modNameSpace, version, groupSym);
2640 
2641  // Figure out whether the body is a single statement or a nested one.
2642  auto stmtIndent = getIndentation();
2643 
2644  // Parsing a single statment is straightforward.
2645  if (!stmtIndent.has_value())
2646  return subParser->parseSimpleStmt(indent);
2647 
2648  if (*stmtIndent <= indent)
2649  return emitError("statement must be indented more than previous statement"),
2650  failure();
2651 
2652  // Parse a block of statements that are indented more than the when.
2653  return subParser->parseSimpleStmtBlock(indent);
2654 }
2655 
2656 /// attach ::= 'attach' '(' exp+ ')' info?
2657 ParseResult FIRStmtParser::parseAttach() {
2658  auto startTok = consumeToken(FIRToken::kw_attach);
2659 
2660  // If this was actually the start of a connect or something else handle that.
2661  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
2662  return *isExpr;
2663 
2664  if (parseToken(FIRToken::l_paren, "expected '(' after attach"))
2665  return failure();
2666 
2667  SmallVector<Value, 4> operands;
2668  do {
2669  operands.push_back({});
2670  if (parseExp(operands.back(), "expected operand in attach"))
2671  return failure();
2672  } while (!consumeIf(FIRToken::r_paren));
2673 
2674  if (parseOptionalInfo())
2675  return failure();
2676 
2677  locationProcessor.setLoc(startTok.getLoc());
2678  builder.create<AttachOp>(operands);
2679  return success();
2680 }
2681 
2682 /// stmt ::= mdir 'mport' id '=' id '[' exp ']' exp info?
2683 /// mdir ::= 'infer' | 'read' | 'write' | 'rdwr'
2684 ///
2685 ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
2686  auto startTok = consumeToken();
2687  auto startLoc = startTok.getLoc();
2688 
2689  // If this was actually the start of a connect or something else handle
2690  // that.
2691  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
2692  return *isExpr;
2693 
2694  StringRef id;
2695  StringRef memName;
2696  SymbolValueEntry memorySym;
2697  Value memory, indexExp, clock;
2698  if (parseToken(FIRToken::kw_mport, "expected 'mport' in memory port") ||
2699  parseId(id, "expected result name") ||
2700  parseToken(FIRToken::equal, "expected '=' in memory port") ||
2701  parseId(memName, "expected memory name") ||
2702  moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
2703  moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
2704  parseToken(FIRToken::l_square, "expected '[' in memory port") ||
2705  parseExp(indexExp, "expected index expression") ||
2706  parseToken(FIRToken::r_square, "expected ']' in memory port") ||
2707  parseExp(clock, "expected clock expression") || parseOptionalInfo())
2708  return failure();
2709 
2710  auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
2711  if (!memVType)
2712  return emitError(startLoc,
2713  "memory port should have behavioral memory type");
2714  auto resultType = memVType.getElementType();
2715 
2716  ArrayAttr annotations = getConstants().emptyArrayAttr;
2717  locationProcessor.setLoc(startLoc);
2718 
2719  // Create the memory port at the location of the cmemory.
2720  Value memoryPort, memoryData;
2721  {
2722  OpBuilder::InsertionGuard guard(builder);
2723  builder.setInsertionPointAfterValue(memory);
2724  auto memoryPortOp = builder.create<MemoryPortOp>(
2725  resultType, CMemoryPortType::get(getContext()), memory, direction, id,
2726  annotations);
2727  memoryData = memoryPortOp.getResult(0);
2728  memoryPort = memoryPortOp.getResult(1);
2729  }
2730 
2731  // Create a memory port access in the current scope.
2732  builder.create<MemoryPortAccessOp>(memoryPort, indexExp, clock);
2733 
2734  return moduleContext.addSymbolEntry(id, memoryData, startLoc, true);
2735 }
2736 
2737 /// printf ::= 'printf(' exp exp StringLit exp* ')' name? info?
2738 ParseResult FIRStmtParser::parsePrintf() {
2739  auto startTok = consumeToken(FIRToken::lp_printf);
2740 
2741  Value clock, condition;
2742  StringRef formatString;
2743  if (parseExp(clock, "expected clock expression in printf") ||
2744  parseExp(condition, "expected condition in printf") ||
2745  parseGetSpelling(formatString) ||
2746  parseToken(FIRToken::string, "expected format string in printf"))
2747  return failure();
2748 
2749  SmallVector<Value, 4> operands;
2750  while (!consumeIf(FIRToken::r_paren)) {
2751  operands.push_back({});
2752  if (parseExp(operands.back(), "expected operand in printf"))
2753  return failure();
2754  }
2755 
2756  StringAttr name;
2757  if (parseOptionalName(name))
2758  return failure();
2759 
2760  if (parseOptionalInfo())
2761  return failure();
2762 
2763  locationProcessor.setLoc(startTok.getLoc());
2764 
2765  auto formatStrUnescaped = FIRToken::getStringValue(formatString);
2766  builder.create<PrintFOp>(clock, condition,
2767  builder.getStringAttr(formatStrUnescaped), operands,
2768  name);
2769  return success();
2770 }
2771 
2772 /// skip ::= 'skip' info?
2773 ParseResult FIRStmtParser::parseSkip() {
2774  auto startTok = consumeToken(FIRToken::kw_skip);
2775 
2776  // If this was actually the start of a connect or something else handle
2777  // that.
2778  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
2779  return *isExpr;
2780 
2781  if (parseOptionalInfo())
2782  return failure();
2783 
2784  locationProcessor.setLoc(startTok.getLoc());
2785  builder.create<SkipOp>();
2786  return success();
2787 }
2788 
2789 /// stop ::= 'stop(' exp exp intLit ')' info?
2790 ParseResult FIRStmtParser::parseStop() {
2791  auto startTok = consumeToken(FIRToken::lp_stop);
2792 
2793  Value clock, condition;
2794  int64_t exitCode;
2795  StringAttr name;
2796  if (parseExp(clock, "expected clock expression in 'stop'") ||
2797  parseExp(condition, "expected condition in 'stop'") ||
2798  parseIntLit(exitCode, "expected exit code in 'stop'") ||
2799  parseToken(FIRToken::r_paren, "expected ')' in 'stop'") ||
2800  parseOptionalName(name) || parseOptionalInfo())
2801  return failure();
2802 
2803  locationProcessor.setLoc(startTok.getLoc());
2804  builder.create<StopOp>(clock, condition, builder.getI32IntegerAttr(exitCode),
2805  name);
2806  return success();
2807 }
2808 
2809 /// assert ::= 'assert(' exp exp exp StringLit ')' info?
2810 ParseResult FIRStmtParser::parseAssert() {
2811  auto startTok = consumeToken(FIRToken::lp_assert);
2812 
2813  Value clock, predicate, enable;
2814  StringRef message;
2815  StringAttr name;
2816  if (parseExp(clock, "expected clock expression in 'assert'") ||
2817  parseExp(predicate, "expected predicate in 'assert'") ||
2818  parseExp(enable, "expected enable in 'assert'") ||
2819  parseGetSpelling(message) ||
2820  parseToken(FIRToken::string, "expected message in 'assert'") ||
2821  parseToken(FIRToken::r_paren, "expected ')' in 'assert'") ||
2822  parseOptionalName(name) || parseOptionalInfo())
2823  return failure();
2824 
2825  locationProcessor.setLoc(startTok.getLoc());
2826  auto messageUnescaped = FIRToken::getStringValue(message);
2827  builder.create<AssertOp>(clock, predicate, enable, messageUnescaped,
2828  ValueRange{}, name.getValue());
2829  return success();
2830 }
2831 
2832 /// assume ::= 'assume(' exp exp exp StringLit ')' info?
2833 ParseResult FIRStmtParser::parseAssume() {
2834  auto startTok = consumeToken(FIRToken::lp_assume);
2835 
2836  Value clock, predicate, enable;
2837  StringRef message;
2838  StringAttr name;
2839  if (parseExp(clock, "expected clock expression in 'assume'") ||
2840  parseExp(predicate, "expected predicate in 'assume'") ||
2841  parseExp(enable, "expected enable in 'assume'") ||
2842  parseGetSpelling(message) ||
2843  parseToken(FIRToken::string, "expected message in 'assume'") ||
2844  parseToken(FIRToken::r_paren, "expected ')' in 'assume'") ||
2845  parseOptionalName(name) || parseOptionalInfo())
2846  return failure();
2847 
2848  locationProcessor.setLoc(startTok.getLoc());
2849  auto messageUnescaped = FIRToken::getStringValue(message);
2850  builder.create<AssumeOp>(clock, predicate, enable, messageUnescaped,
2851  ValueRange{}, name.getValue());
2852  return success();
2853 }
2854 
2855 /// cover ::= 'cover(' exp exp exp StringLit ')' info?
2856 ParseResult FIRStmtParser::parseCover() {
2857  auto startTok = consumeToken(FIRToken::lp_cover);
2858 
2859  Value clock, predicate, enable;
2860  StringRef message;
2861  StringAttr name;
2862  if (parseExp(clock, "expected clock expression in 'cover'") ||
2863  parseExp(predicate, "expected predicate in 'cover'") ||
2864  parseExp(enable, "expected enable in 'cover'") ||
2865  parseGetSpelling(message) ||
2866  parseToken(FIRToken::string, "expected message in 'cover'") ||
2867  parseToken(FIRToken::r_paren, "expected ')' in 'cover'") ||
2868  parseOptionalName(name) || parseOptionalInfo())
2869  return failure();
2870 
2871  locationProcessor.setLoc(startTok.getLoc());
2872  auto messageUnescaped = FIRToken::getStringValue(message);
2873  builder.create<CoverOp>(clock, predicate, enable, messageUnescaped,
2874  ValueRange{}, name.getValue());
2875  return success();
2876 }
2877 
2878 /// when ::= 'when' exp ':' info? suite? ('else' ( when | ':' info? suite?)
2879 /// )? suite ::= simple_stmt | INDENT simple_stmt+ DEDENT
2880 ParseResult FIRStmtParser::parseWhen(unsigned whenIndent) {
2881  auto startTok = consumeToken(FIRToken::kw_when);
2882 
2883  // If this was actually the start of a connect or something else handle
2884  // that.
2885  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
2886  return *isExpr;
2887 
2888  Value condition;
2889  if (parseExp(condition, "expected condition in 'when'") ||
2890  parseToken(FIRToken::colon, "expected ':' in when") ||
2891  parseOptionalInfo())
2892  return failure();
2893 
2894  locationProcessor.setLoc(startTok.getLoc());
2895  // Create the IR representation for the when.
2896  auto whenStmt = builder.create<WhenOp>(condition, /*createElse*/ false);
2897 
2898  // Parse the 'then' body into the 'then' region.
2899  if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, groupSym))
2900  return failure();
2901 
2902  // If the else is present, handle it otherwise we're done.
2903  if (getToken().isNot(FIRToken::kw_else))
2904  return success();
2905 
2906  // If the 'else' is less indented than the when, then it must belong to some
2907  // containing 'when'.
2908  auto elseIndent = getIndentation();
2909  if (elseIndent && *elseIndent < whenIndent)
2910  return success();
2911 
2912  consumeToken(FIRToken::kw_else);
2913 
2914  // Create an else block to parse into.
2915  whenStmt.createElseRegion();
2916 
2917  // If we have the ':' form, then handle it.
2918 
2919  // Syntactic shorthand 'else when'. This uses the same indentation level as
2920  // the outer 'when'.
2921  if (getToken().is(FIRToken::kw_when)) {
2922  // We create a sub parser for the else block.
2923  auto subParser =
2924  std::make_unique<FIRStmtParser>(whenStmt.getElseBlock(), moduleContext,
2925  modNameSpace, version, groupSym);
2926 
2927  return subParser->parseSimpleStmt(whenIndent);
2928  }
2929 
2930  // Parse the 'else' body into the 'else' region.
2931  LocationAttr elseLoc; // ignore the else locator.
2932  if (parseToken(FIRToken::colon, "expected ':' after 'else'") ||
2933  parseOptionalInfoLocator(elseLoc) ||
2934  parseSubBlock(whenStmt.getElseBlock(), whenIndent, groupSym))
2935  return failure();
2936 
2937  // TODO(firrtl spec): There is no reason for the 'else :' grammar to take an
2938  // info. It doesn't appear to be generated either.
2939  return success();
2940 }
2941 
2942 /// enum-exp ::= enum-type '(' Id ( ',' exp )? ')'
2943 ParseResult FIRStmtParser::parseEnumExp(Value &value) {
2944  auto startLoc = getToken().getLoc();
2945  FIRRTLType type;
2946  if (parseEnumType(type))
2947  return failure();
2948 
2949  // Check that the input type is a legal enumeration.
2950  auto enumType = type_dyn_cast<FEnumType>(type);
2951  if (!enumType)
2952  return emitError(startLoc,
2953  "expected enumeration type in enumeration expression");
2954 
2955  StringRef tag;
2956  if (parseToken(FIRToken::l_paren, "expected '(' in enumeration expression") ||
2957  parseId(tag, "expected enumeration tag"))
2958  return failure();
2959 
2960  Value input;
2961  if (consumeIf(FIRToken::r_paren)) {
2962  // If the payload is not specified, we create a 0 bit unsigned integer
2963  // constant.
2964  auto type = IntType::get(builder.getContext(), false, 0);
2965  Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
2966  auto attr = builder.getIntegerAttr(attrType, APInt(0, 0, false));
2967  input = builder.create<ConstantOp>(type, attr);
2968  } else {
2969  // Otherwise we parse an expression.
2970  if (parseExp(input, "expected expression in enumeration value") ||
2971  parseToken(FIRToken::r_paren, "expected closing ')'"))
2972  return failure();
2973  }
2974 
2975  locationProcessor.setLoc(startLoc);
2976  value = builder.create<FEnumCreateOp>(enumType, tag, input);
2977  return success();
2978 }
2979 
2980 /// match ::= 'match' exp ':' info?
2981 /// (INDENT ( Id ( '(' Id ')' )? ':'
2982 /// (INDENT simple_stmt* DEDENT )?
2983 /// )* DEDENT)?
2984 ParseResult FIRStmtParser::parseMatch(unsigned matchIndent) {
2985  auto startTok = consumeToken(FIRToken::kw_match);
2986 
2987  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
2988  return *isExpr;
2989 
2990  Value input;
2991  if (parseExp(input, "expected expression in 'match'") ||
2992  parseToken(FIRToken::colon, "expected ':' in 'match'") ||
2993  parseOptionalInfo())
2994  return failure();
2995 
2996  auto enumType = type_dyn_cast<FEnumType>(input.getType());
2997  if (!enumType)
2998  return mlir::emitError(
2999  input.getLoc(),
3000  "expected enumeration type for 'match' statement, but got ")
3001  << input.getType();
3002 
3003  locationProcessor.setLoc(startTok.getLoc());
3004 
3005  SmallVector<Attribute> tags;
3006  SmallVector<std::unique_ptr<Region>> regions;
3007  while (true) {
3008  auto tagLoc = getToken().getLoc();
3009 
3010  // Only consume the keyword if the indentation is correct.
3011  auto caseIndent = getIndentation();
3012  if (!caseIndent || *caseIndent <= matchIndent)
3013  break;
3014 
3015  // Parse the tag.
3016  StringRef tagSpelling;
3017  if (parseId(tagSpelling, "expected enumeration tag in match statement"))
3018  return failure();
3019  auto tagIndex = enumType.getElementIndex(tagSpelling);
3020  if (!tagIndex)
3021  return emitError(tagLoc, "tag ")
3022  << tagSpelling << " not a member of enumeration " << enumType;
3023  auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3024  tags.push_back(tag);
3025 
3026  // Add a new case to the match operation.
3027  auto *caseBlock = &regions.emplace_back(new Region)->emplaceBlock();
3028 
3029  // Declarations are scoped to the case.
3030  FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3031 
3032  // After parsing the region, we can release any new entries in
3033  // unbundledValues since the symbol table entries that refer to them will be
3034  // gone.
3035  UnbundledValueRestorer x(moduleContext.unbundledValues);
3036 
3037  // Parse the argument.
3038  if (consumeIf(FIRToken::l_paren)) {
3039  StringAttr identifier;
3040  if (parseId(identifier, "expected identifier for 'case' binding"))
3041  return failure();
3042 
3043  // Add an argument to the block.
3044  auto dataType = enumType.getElementType(*tagIndex);
3045  caseBlock->addArgument(dataType, LocWithInfo(tagLoc, this).getLoc());
3046 
3047  if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3048  startTok.getLoc()))
3049  return failure();
3050 
3051  if (parseToken(FIRToken::r_paren, "expected ')' in match statement case"))
3052  return failure();
3053 
3054  } else {
3055  auto dataType = IntType::get(builder.getContext(), false, 0);
3056  caseBlock->addArgument(dataType, LocWithInfo(tagLoc, this).getLoc());
3057  }
3058 
3059  if (parseToken(FIRToken::colon, "expected ':' in match statement case"))
3060  return failure();
3061 
3062  // Parse a block of statements that are indented more than the case.
3063  auto subParser = std::make_unique<FIRStmtParser>(
3064  *caseBlock, moduleContext, modNameSpace, version, groupSym);
3065  if (subParser->parseSimpleStmtBlock(*caseIndent))
3066  return failure();
3067  }
3068 
3069  builder.create<MatchOp>(input, ArrayAttr::get(getContext(), tags), regions);
3070  return success();
3071 }
3072 
3073 /// ref_expr ::= probe | rwprobe | static_reference
3074 // NOLINTNEXTLINE(misc-no-recursion)
3075 ParseResult FIRStmtParser::parseRefExp(Value &result, const Twine &message) {
3076  auto token = getToken().getKind();
3077  if (token == FIRToken::lp_probe)
3078  return parseProbe(result);
3079  if (token == FIRToken::lp_rwprobe)
3080  return parseRWProbe(result);
3081 
3082  // Default to parsing as static reference expression.
3083  // Don't check token kind, we need to support literal_identifier and keywords,
3084  // let parseId handle this.
3085  return parseStaticRefExp(result, message);
3086 }
3087 
3088 /// static_reference ::= id
3089 /// ::= static_reference '.' id
3090 /// ::= static_reference '[' int ']'
3091 // NOLINTNEXTLINE(misc-no-recursion)
3092 ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3093  const Twine &message) {
3094  auto parseIdOrInstance = [&]() -> ParseResult {
3095  StringRef id;
3096  auto loc = getToken().getLoc();
3097  SymbolValueEntry symtabEntry;
3098  if (parseId(id, message) ||
3099  moduleContext.lookupSymbolEntry(symtabEntry, id, loc))
3100  return failure();
3101 
3102  // If we looked up a normal value, then we're done.
3103  if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc, false))
3104  return success();
3105 
3106  assert(symtabEntry.is<UnbundledID>() && "should be an instance");
3107 
3108  // Handle the normal "instance.x" reference.
3109  StringRef fieldName;
3110  return failure(
3111  parseToken(FIRToken::period, "expected '.' in field reference") ||
3112  parseFieldId(fieldName, "expected field name") ||
3113  moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3114  };
3115  return failure(parseIdOrInstance() ||
3116  parseOptionalExpPostscript(result, false));
3117 }
3118 
3119 /// path ::= 'path(' StringLit ')'
3120 // NOLINTNEXTLINE(misc-no-recursion)
3121 ParseResult FIRStmtParser::parsePathExp(Value &result) {
3122  auto startTok = consumeToken(FIRToken::lp_path);
3123  locationProcessor.setLoc(startTok.getLoc());
3124  StringRef target;
3125  if (parseGetSpelling(target) ||
3126  parseToken(FIRToken::string,
3127  "expected target string in path expression") ||
3128  parseToken(FIRToken::r_paren, "expected ')' in path expression"))
3129  return failure();
3130  result = builder.create<UnresolvedPathOp>(
3131  StringAttr::get(getContext(), FIRToken::getStringValue(target)));
3132  return success();
3133 }
3134 
3135 /// define ::= 'define' static_reference '=' ref_expr info?
3136 ParseResult FIRStmtParser::parseRefDefine() {
3137  auto startTok = consumeToken(FIRToken::kw_define);
3138 
3139  Value src, target;
3140  if (parseStaticRefExp(target,
3141  "expected static reference expression in 'define'") ||
3142  parseToken(FIRToken::equal,
3143  "expected '=' after define reference expression") ||
3144  parseRefExp(src, "expected reference expression in 'define'") ||
3145  parseOptionalInfo())
3146  return failure();
3147 
3148  // Check reference expressions are of reference type.
3149  if (!type_isa<RefType>(target.getType()))
3150  return emitError(startTok.getLoc(), "expected reference-type expression in "
3151  "'define' target (LHS), got ")
3152  << target.getType();
3153  if (!type_isa<RefType>(src.getType()))
3154  return emitError(startTok.getLoc(), "expected reference-type expression in "
3155  "'define' source (RHS), got ")
3156  << src.getType();
3157 
3158  // static_reference doesn't differentiate which can be ref.sub'd, so check
3159  // this explicitly:
3160  if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
3161  return emitError(startTok.getLoc(),
3162  "cannot define into a sub-element of a reference");
3163 
3164  locationProcessor.setLoc(startTok.getLoc());
3165 
3166  if (!areTypesRefCastable(target.getType(), src.getType()))
3167  return emitError(startTok.getLoc(), "cannot define reference of type ")
3168  << target.getType() << " with incompatible reference of type "
3169  << src.getType();
3170 
3171  emitConnect(builder, target, src);
3172 
3173  return success();
3174 }
3175 
3176 /// read ::= '(' ref_expr ')'
3177 /// XXX: spec says static_reference, allow ref_expr anyway for read(probe(x)).
3178 ParseResult FIRStmtParser::parseRefRead(Value &result) {
3179  auto startTok = consumeToken(FIRToken::lp_read);
3180 
3181  Value ref;
3182  if (parseRefExp(ref, "expected reference expression in 'read'") ||
3183  parseToken(FIRToken::r_paren, "expected ')' in 'read'"))
3184  return failure();
3185 
3186  locationProcessor.setLoc(startTok.getLoc());
3187 
3188  // Check argument is a ref-type value.
3189  if (!type_isa<RefType>(ref.getType()))
3190  return emitError(startTok.getLoc(),
3191  "expected reference-type expression in 'read', got ")
3192  << ref.getType();
3193 
3194  result = builder.create<RefResolveOp>(ref);
3195 
3196  return success();
3197 }
3198 
3199 /// probe ::= 'probe' '(' static_ref ')'
3200 ParseResult FIRStmtParser::parseProbe(Value &result) {
3201  auto startTok = consumeToken(FIRToken::lp_probe);
3202 
3203  Value staticRef;
3204  if (parseStaticRefExp(staticRef,
3205  "expected static reference expression in 'probe'") ||
3206  parseToken(FIRToken::r_paren, "expected ')' in 'probe'"))
3207  return failure();
3208 
3209  locationProcessor.setLoc(startTok.getLoc());
3210 
3211  // Check probe expression is base-type.
3212  if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
3213  return emitError(startTok.getLoc(),
3214  "expected base-type expression in 'probe', got ")
3215  << staticRef.getType();
3216 
3217  // Check for other unsupported reference sources.
3218  // TODO: Add to ref.send verifier / inferReturnTypes.
3219  if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
3220  MemoryDebugPortOp, MemoryPortAccessOp>(
3221  staticRef.getDefiningOp()))
3222  return emitError(startTok.getLoc(), "cannot probe memories or their ports");
3223 
3224  result = builder.create<RefSendOp>(staticRef);
3225 
3226  return success();
3227 }
3228 
3229 /// rwprobe ::= 'rwprobe' '(' static_ref ')'
3230 ParseResult FIRStmtParser::parseRWProbe(Value &result) {
3231  auto startTok = consumeToken(FIRToken::lp_rwprobe);
3232 
3233  Value staticRef;
3234  if (parseStaticRefExp(staticRef,
3235  "expected static reference expression in 'rwprobe'") ||
3236  parseToken(FIRToken::r_paren, "expected ')' in 'rwprobe'"))
3237  return failure();
3238 
3239  locationProcessor.setLoc(startTok.getLoc());
3240 
3241  // Checks:
3242  // Not public port (verifier)
3243 
3244  // Check probe expression is base-type.
3245  auto targetType = type_dyn_cast<FIRRTLBaseType>(staticRef.getType());
3246  if (!targetType)
3247  return emitError(startTok.getLoc(),
3248  "expected base-type expression in 'rwprobe', got ")
3249  << staticRef.getType();
3250 
3251  auto fieldRef = getFieldRefFromValue(staticRef);
3252  auto target = fieldRef.getValue();
3253 
3254  // Ports are handled differently, emit a RWProbeOp with inner symbol.
3255  if (auto arg = dyn_cast<BlockArgument>(target)) {
3256  // Check target type.
3257  if (targetType.hasUninferredReset())
3258  return emitError(startTok.getLoc(),
3259  "must have concrete reset type in type ")
3260  << targetType;
3261  auto forceableType =
3262  firrtl::detail::getForceableResultType(true, targetType);
3263  if (!forceableType)
3264  return emitError(startTok.getLoc(), "cannot force target of type ")
3265  << targetType;
3266 
3267  // Get InnerRef for target field.
3268  auto mod = cast<FModuleOp>(arg.getOwner()->getParentOp());
3269  auto sym = getInnerRefTo(
3270  hw::InnerSymTarget(arg.getArgNumber(), mod, fieldRef.getFieldID()),
3271  [&](auto _) -> hw::InnerSymbolNamespace & { return modNameSpace; });
3272  result = builder.create<RWProbeOp>(forceableType, sym);
3273  return success();
3274  }
3275 
3276  auto *definingOp = target.getDefiningOp();
3277  if (!definingOp)
3278  return emitError(startTok.getLoc(),
3279  "rwprobe value must be defined by an operation");
3280 
3281  if (isa<MemOp, CombMemOp, SeqMemOp, MemoryPortOp, MemoryDebugPortOp,
3282  MemoryPortAccessOp>(definingOp))
3283  return emitError(startTok.getLoc(), "cannot probe memories or their ports");
3284 
3285  auto forceable = dyn_cast<Forceable>(definingOp);
3286  if (!forceable || !forceable.isForceable() /* e.g., is/has const type*/)
3287  return emitError(startTok.getLoc(), "rwprobe target not forceable")
3288  .attachNote(definingOp->getLoc());
3289 
3290  // TODO: do the ref.sub work while parsing the static expression.
3291  result =
3292  getValueByFieldID(builder, forceable.getDataRef(), fieldRef.getFieldID());
3293 
3294  return success();
3295 }
3296 
3297 /// force ::= 'force(' exp exp ref_expr exp ')' info?
3298 ParseResult FIRStmtParser::parseRefForce() {
3299  auto startTok = consumeToken(FIRToken::lp_force);
3300 
3301  Value clock, pred, dest, src;
3302  if (parseExp(clock, "expected clock expression in force") ||
3303  parseExp(pred, "expected predicate expression in force") ||
3304  parseRefExp(dest, "expected destination reference expression in force") ||
3305  parseExp(src, "expected source expression in force") ||
3306  parseToken(FIRToken::r_paren, "expected ')' in force") ||
3307  parseOptionalInfo())
3308  return failure();
3309 
3310  // Check reference expression is of reference type.
3311  auto ref = type_dyn_cast<RefType>(dest.getType());
3312  if (!ref || !ref.getForceable())
3313  return emitError(
3314  startTok.getLoc(),
3315  "expected rwprobe-type expression for force destination, got ")
3316  << dest.getType();
3317  auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3318  if (!srcBaseType)
3319  return emitError(startTok.getLoc(),
3320  "expected base-type for force source, got ")
3321  << src.getType();
3322 
3323  locationProcessor.setLoc(startTok.getLoc());
3324 
3325  // Cast ref to accomodate uninferred sources.
3326  auto noConstSrcType = srcBaseType.getAllConstDroppedType();
3327  if (noConstSrcType != ref.getType()) {
3328  // Try to cast destination to rwprobe of source type (dropping const).
3329  auto compatibleRWProbe = RefType::get(noConstSrcType, true);
3330  if (areTypesRefCastable(compatibleRWProbe, ref))
3331  dest = builder.create<RefCastOp>(compatibleRWProbe, dest);
3332  }
3333 
3334  builder.create<RefForceOp>(clock, pred, dest, src);
3335 
3336  return success();
3337 }
3338 
3339 /// force_initial ::= 'force_initial(' ref_expr exp ')' info?
3340 ParseResult FIRStmtParser::parseRefForceInitial() {
3341  auto startTok = consumeToken(FIRToken::lp_force_initial);
3342 
3343  Value dest, src;
3344  if (parseRefExp(
3345  dest, "expected destination reference expression in force_initial") ||
3346  parseExp(src, "expected source expression in force_initial") ||
3347  parseToken(FIRToken::r_paren, "expected ')' in force_initial") ||
3348  parseOptionalInfo())
3349  return failure();
3350 
3351  // Check reference expression is of reference type.
3352  auto ref = type_dyn_cast<RefType>(dest.getType());
3353  if (!ref || !ref.getForceable())
3354  return emitError(startTok.getLoc(), "expected rwprobe-type expression for "
3355  "force_initial destination, got ")
3356  << dest.getType();
3357  auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3358  if (!srcBaseType)
3359  return emitError(startTok.getLoc(),
3360  "expected base-type expression for force_initial "
3361  "source, got ")
3362  << src.getType();
3363 
3364  locationProcessor.setLoc(startTok.getLoc());
3365 
3366  // Cast ref to accomodate uninferred sources.
3367  auto noConstSrcType = srcBaseType.getAllConstDroppedType();
3368  if (noConstSrcType != ref.getType()) {
3369  // Try to cast destination to rwprobe of source type (dropping const).
3370  auto compatibleRWProbe = RefType::get(noConstSrcType, true);
3371  if (areTypesRefCastable(compatibleRWProbe, ref))
3372  dest = builder.create<RefCastOp>(compatibleRWProbe, dest);
3373  }
3374 
3375  auto value = APInt::getAllOnes(1);
3376  auto type = UIntType::get(builder.getContext(), 1);
3377  auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
3378  value.getBitWidth(),
3379  IntegerType::Unsigned),
3380  value);
3381  auto pred = moduleContext.getCachedConstantInt(builder, attr, type, value);
3382  builder.create<RefForceInitialOp>(pred, dest, src);
3383 
3384  return success();
3385 }
3386 
3387 /// release ::= 'release(' exp exp ref_expr ')' info?
3388 ParseResult FIRStmtParser::parseRefRelease() {
3389  auto startTok = consumeToken(FIRToken::lp_release);
3390 
3391  Value clock, pred, dest;
3392  if (parseExp(clock, "expected clock expression in release") ||
3393  parseExp(pred, "expected predicate expression in release") ||
3394  parseRefExp(dest,
3395  "expected destination reference expression in release") ||
3396  parseToken(FIRToken::r_paren, "expected ')' in release") ||
3397  parseOptionalInfo())
3398  return failure();
3399 
3400  // Check reference expression is of reference type.
3401  if (auto ref = type_dyn_cast<RefType>(dest.getType());
3402  !ref || !ref.getForceable())
3403  return emitError(
3404  startTok.getLoc(),
3405  "expected rwprobe-type expression for release destination, got ")
3406  << dest.getType();
3407 
3408  locationProcessor.setLoc(startTok.getLoc());
3409 
3410  builder.create<RefReleaseOp>(clock, pred, dest);
3411 
3412  return success();
3413 }
3414 
3415 /// release_initial ::= 'release_initial(' ref_expr ')' info?
3416 ParseResult FIRStmtParser::parseRefReleaseInitial() {
3417  auto startTok = consumeToken(FIRToken::lp_release_initial);
3418 
3419  Value dest;
3420  if (parseRefExp(
3421  dest,
3422  "expected destination reference expression in release_initial") ||
3423  parseToken(FIRToken::r_paren, "expected ')' in release_initial") ||
3424  parseOptionalInfo())
3425  return failure();
3426 
3427  // Check reference expression is of reference type.
3428  if (auto ref = type_dyn_cast<RefType>(dest.getType());
3429  !ref || !ref.getForceable())
3430  return emitError(startTok.getLoc(), "expected rwprobe-type expression for "
3431  "release_initial destination, got ")
3432  << dest.getType();
3433 
3434  locationProcessor.setLoc(startTok.getLoc());
3435 
3436  auto value = APInt::getAllOnes(1);
3437  auto type = UIntType::get(builder.getContext(), 1);
3438  auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
3439  value.getBitWidth(),
3440  IntegerType::Unsigned),
3441  value);
3442  auto pred = moduleContext.getCachedConstantInt(builder, attr, type, value);
3443  builder.create<RefReleaseInitialOp>(pred, dest);
3444 
3445  return success();
3446 }
3447 
3448 /// connect ::= 'connect' expr expr
3449 ParseResult FIRStmtParser::parseConnect() {
3450  auto startTok = consumeToken(FIRToken::kw_connect);
3451  auto loc = startTok.getLoc();
3452 
3453  Value lhs, rhs;
3454  if (parseExp(lhs, "expected connect expression") ||
3455  parseExp(rhs, "expected connect expression") || parseOptionalInfo())
3456  return failure();
3457 
3458  auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
3459  auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
3460  if (!lhsType || !rhsType)
3461  return emitError(loc, "cannot connect reference or property types");
3462  // TODO: Once support lands for agg-of-ref, add test for this check!
3463  if (lhsType.containsReference() || rhsType.containsReference())
3464  return emitError(loc, "cannot connect types containing references");
3465 
3466  if (!areTypesEquivalent(lhsType, rhsType))
3467  return emitError(loc, "cannot connect non-equivalent type ")
3468  << rhsType << " to " << lhsType;
3469 
3470  locationProcessor.setLoc(loc);
3471  emitConnect(builder, lhs, rhs);
3472  return success();
3473 }
3474 
3475 /// propassign ::= 'propassign' expr expr
3476 ParseResult FIRStmtParser::parsePropAssign() {
3477  auto startTok = consumeToken(FIRToken::kw_propassign);
3478  auto loc = startTok.getLoc();
3479 
3480  Value lhs, rhs;
3481  if (parseExp(lhs, "expected propassign expression") ||
3482  parseExp(rhs, "expected propassign expression") || parseOptionalInfo())
3483  return failure();
3484 
3485  auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
3486  auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
3487  if (!lhsType || !rhsType)
3488  return emitError(loc, "can only propassign property types");
3489  locationProcessor.setLoc(loc);
3490  if (lhsType != rhsType) {
3491  // If the lhs is anyref, and the rhs is a ClassType, insert a cast.
3492  if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
3493  rhs = builder.create<ObjectAnyRefCastOp>(rhs);
3494  else
3495  return emitError(loc, "cannot propassign non-equivalent type ")
3496  << rhsType << " to " << lhsType;
3497  }
3498  builder.create<PropAssignOp>(lhs, rhs);
3499  return success();
3500 }
3501 
3502 /// invalidate ::= 'invalidate' expr
3503 ParseResult FIRStmtParser::parseInvalidate() {
3504  auto startTok = consumeToken(FIRToken::kw_invalidate);
3505 
3506  Value lhs;
3507  if (parseExp(lhs, "expected connect expression") || parseOptionalInfo())
3508  return failure();
3509 
3510  locationProcessor.setLoc(startTok.getLoc());
3511  emitInvalidate(lhs);
3512  return success();
3513 }
3514 
3515 ParseResult FIRStmtParser::parseGroup(unsigned indent) {
3516 
3517  auto startTok = consumeToken(FIRToken::kw_group);
3518  auto loc = startTok.getLoc();
3519 
3520  StringRef id;
3521  if (parseId(id, "expected group identifer") ||
3522  parseToken(FIRToken::colon, "expected ':' at end of group") ||
3523  parseOptionalInfo())
3524  return failure();
3525 
3526  locationProcessor.setLoc(loc);
3527 
3528  StringRef rootGroup;
3529  SmallVector<FlatSymbolRefAttr> nestedGroups;
3530  if (!groupSym) {
3531  rootGroup = id;
3532  } else {
3533  rootGroup = groupSym.getRootReference();
3534  auto nestedRefs = groupSym.getNestedReferences();
3535  nestedGroups.append(nestedRefs.begin(), nestedRefs.end());
3536  nestedGroups.push_back(FlatSymbolRefAttr::get(builder.getContext(), id));
3537  }
3538 
3539  auto groupOp = builder.create<GroupOp>(
3540  SymbolRefAttr::get(builder.getContext(), rootGroup, nestedGroups));
3541  groupOp->getRegion(0).push_back(new Block());
3542 
3543  if (getIndentation() > indent)
3544  if (parseSubBlock(groupOp.getRegion().front(), indent,
3545  groupOp.getGroupName()))
3546  return failure();
3547 
3548  return success();
3549 }
3550 
3551 /// leading-exp-stmt ::= exp '<=' exp info?
3552 /// ::= exp '<-' exp info?
3553 /// ::= exp 'is' 'invalid' info?
3554 ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
3555  auto loc = getToken().getLoc();
3556 
3557  // If 'is' grammar is special.
3558  if (consumeIf(FIRToken::kw_is)) {
3559  if (parseToken(FIRToken::kw_invalid, "expected 'invalid'") ||
3560  parseOptionalInfo())
3561  return failure();
3562 
3563  locationProcessor.setLoc(loc);
3564  emitInvalidate(lhs);
3565  return success();
3566  }
3567 
3568  auto kind = getToken().getKind();
3569  switch (kind) {
3570  case FIRToken::less_equal:
3571  break;
3572  case FIRToken::less_minus:
3573  // Partial connect ("<-") was removed in FIRRTL version 2.0.0.
3574  if (version < FIRVersion(2, 0, 0))
3575  break;
3576  [[fallthrough]];
3577  default:
3578  return emitError() << "unexpected token '" << getToken().getSpelling()
3579  << "' in statement",
3580  failure();
3581  }
3582  consumeToken();
3583 
3584  Value rhs;
3585  if (parseExp(rhs, "unexpected token in statement") || parseOptionalInfo())
3586  return failure();
3587 
3588  locationProcessor.setLoc(loc);
3589 
3590  auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
3591  auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
3592  if (!lhsType || !rhsType)
3593  return emitError(loc, "cannot connect reference or property types");
3594  // TODO: Once support lands for agg-of-ref, add test for this check!
3595  if (lhsType.containsReference() || rhsType.containsReference())
3596  return emitError(loc, "cannot connect types containing references");
3597 
3598  if (kind == FIRToken::less_equal) {
3599  if (!areTypesEquivalent(lhsType, rhsType))
3600  return emitError(loc, "cannot connect non-equivalent type ")
3601  << rhsType << " to " << lhsType;
3602  emitConnect(builder, lhs, rhs);
3603  } else {
3604  assert(kind == FIRToken::less_minus && "unexpected kind");
3605  if (!areTypesWeaklyEquivalent(lhsType, rhsType))
3606  return emitError(loc,
3607  "cannot partially connect non-weakly-equivalent type ")
3608  << rhsType << " to " << lhsType;
3609  emitPartialConnect(builder, lhs, rhs);
3610  }
3611  return success();
3612 }
3613 
3614 //===-------------------------------
3615 // FIRStmtParser Declaration Parsing
3616 
3617 /// instance ::= 'inst' id 'of' id info?
3618 ParseResult FIRStmtParser::parseInstance() {
3619  auto startTok = consumeToken(FIRToken::kw_inst);
3620 
3621  // If this was actually the start of a connect or something else handle
3622  // that.
3623  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3624  return *isExpr;
3625 
3626  StringRef id;
3627  StringRef moduleName;
3628  if (parseId(id, "expected instance name") ||
3629  parseToken(FIRToken::kw_of, "expected 'of' in instance") ||
3630  parseId(moduleName, "expected module name") || parseOptionalInfo())
3631  return failure();
3632 
3633  locationProcessor.setLoc(startTok.getLoc());
3634 
3635  // Look up the module that is being referenced.
3636  auto circuit =
3637  builder.getBlock()->getParentOp()->getParentOfType<CircuitOp>();
3638  auto referencedModule =
3639  dyn_cast_or_null<FModuleLike>(circuit.lookupSymbol(moduleName));
3640  if (!referencedModule) {
3641  emitError(startTok.getLoc(),
3642  "use of undefined module name '" + moduleName + "' in instance");
3643  return failure();
3644  }
3645  if (isa<ClassOp /* ClassLike */>(referencedModule))
3646  return emitError(startTok.getLoc(), "cannot create instance of class '" +
3647  moduleName +
3648  "', did you mean object?");
3649 
3650  SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
3651 
3652  // Make a bundle of the inputs and outputs of the specified module.
3653  SmallVector<Type, 4> resultTypes;
3654  resultTypes.reserve(modulePorts.size());
3655  SmallVector<std::pair<StringAttr, Type>, 4> resultNamesAndTypes;
3656 
3657  for (auto port : modulePorts) {
3658  resultTypes.push_back(port.type);
3659  resultNamesAndTypes.push_back({port.name, port.type});
3660  }
3661 
3662  auto annotations = getConstants().emptyArrayAttr;
3663  SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
3664 
3665  StringAttr sym = {};
3666  auto result = builder.create<InstanceOp>(
3667  referencedModule, id, NameKindEnum::InterestingName,
3668  annotations.getValue(), portAnnotations, false, sym);
3669 
3670  // Since we are implicitly unbundling the instance results, we need to keep
3671  // track of the mapping from bundle fields to results in the unbundledValues
3672  // data structure. Build our entry now.
3673  UnbundledValueEntry unbundledValueEntry;
3674  unbundledValueEntry.reserve(modulePorts.size());
3675  for (size_t i = 0, e = modulePorts.size(); i != e; ++i)
3676  unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
3677 
3678  // Add it to unbundledValues and add an entry to the symbol table to remember
3679  // it.
3680  moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
3681  auto entryId = UnbundledID(moduleContext.unbundledValues.size());
3682  return moduleContext.addSymbolEntry(id, entryId, startTok.getLoc());
3683 }
3684 
3685 /// object ::= 'object' id 'of' id info?
3686 ParseResult FIRStmtParser::parseObject() {
3687  auto startTok = consumeToken(FIRToken::kw_object);
3688 
3689  // If this was actually the start of a connect or something else handle
3690  // that.
3691  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3692  return *isExpr;
3693 
3694  if (requireFeature({3, 2, 0}, "object statements"))
3695  return failure();
3696 
3697  StringRef id;
3698  StringRef className;
3699  if (parseId(id, "expected object name") ||
3700  parseToken(FIRToken::kw_of, "expected 'of' in object") ||
3701  parseId(className, "expected class name") || parseOptionalInfo())
3702  return failure();
3703 
3704  locationProcessor.setLoc(startTok.getLoc());
3705 
3706  // Look up the class that is being referenced.
3707  auto circuit =
3708  builder.getBlock()->getParentOp()->getParentOfType<CircuitOp>();
3709  auto referencedClass = circuit.lookupSymbol<ClassLike>(className);
3710  if (!referencedClass)
3711  return emitError(startTok.getLoc(), "use of undefined class name '" +
3712  className + "' in object");
3713  auto result = builder.create<ObjectOp>(referencedClass, id);
3714  return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
3715 }
3716 
3717 /// cmem ::= 'cmem' id ':' type info?
3718 ParseResult FIRStmtParser::parseCombMem() {
3719  // TODO(firrtl spec) cmem is completely undocumented.
3720  auto startTok = consumeToken(FIRToken::kw_cmem);
3721 
3722  // If this was actually the start of a connect or something else handle
3723  // that.
3724  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3725  return *isExpr;
3726 
3727  StringRef id;
3728  FIRRTLType type;
3729  if (parseId(id, "expected cmem name") ||
3730  parseToken(FIRToken::colon, "expected ':' in cmem") ||
3731  parseType(type, "expected cmem type") || parseOptionalInfo())
3732  return failure();
3733 
3734  locationProcessor.setLoc(startTok.getLoc());
3735 
3736  // Transform the parsed vector type into a memory type.
3737  auto vectorType = type_dyn_cast<FVectorType>(type);
3738  if (!vectorType)
3739  return emitError("cmem requires vector type");
3740 
3741  auto annotations = getConstants().emptyArrayAttr;
3742  StringAttr sym = {};
3743  auto result = builder.create<CombMemOp>(
3744  vectorType.getElementType(), vectorType.getNumElements(), id,
3745  NameKindEnum::InterestingName, annotations, sym);
3746  return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
3747 }
3748 
3749 /// smem ::= 'smem' id ':' type ruw? info?
3750 ParseResult FIRStmtParser::parseSeqMem() {
3751  // TODO(firrtl spec) smem is completely undocumented.
3752  auto startTok = consumeToken(FIRToken::kw_smem);
3753 
3754  // If this was actually the start of a connect or something else handle
3755  // that.
3756  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3757  return *isExpr;
3758 
3759  StringRef id;
3760  FIRRTLType type;
3761  RUWAttr ruw = RUWAttr::Undefined;
3762 
3763  if (parseId(id, "expected smem name") ||
3764  parseToken(FIRToken::colon, "expected ':' in smem") ||
3765  parseType(type, "expected smem type") || parseOptionalRUW(ruw) ||
3766  parseOptionalInfo())
3767  return failure();
3768 
3769  locationProcessor.setLoc(startTok.getLoc());
3770 
3771  // Transform the parsed vector type into a memory type.
3772  auto vectorType = type_dyn_cast<FVectorType>(type);
3773  if (!vectorType)
3774  return emitError("smem requires vector type");
3775 
3776  auto annotations = getConstants().emptyArrayAttr;
3777  StringAttr sym = {};
3778  auto result = builder.create<SeqMemOp>(
3779  vectorType.getElementType(), vectorType.getNumElements(), ruw, id,
3780  NameKindEnum::InterestingName, annotations, sym);
3781  return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
3782 }
3783 
3784 /// mem ::= 'mem' id ':' info? INDENT memField* DEDENT
3785 /// memField ::= 'data-type' '=>' type NEWLINE
3786 /// ::= 'depth' '=>' intLit NEWLINE
3787 /// ::= 'read-latency' '=>' intLit NEWLINE
3788 /// ::= 'write-latency' '=>' intLit NEWLINE
3789 /// ::= 'read-under-write' '=>' ruw NEWLINE
3790 /// ::= 'reader' '=>' id+ NEWLINE
3791 /// ::= 'writer' '=>' id+ NEWLINE
3792 /// ::= 'readwriter' '=>' id+ NEWLINE
3793 ParseResult FIRStmtParser::parseMem(unsigned memIndent) {
3794  auto startTok = consumeToken(FIRToken::kw_mem);
3795 
3796  // If this was actually the start of a connect or something else handle
3797  // that.
3798  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3799  return *isExpr;
3800 
3801  StringRef id;
3802  if (parseId(id, "expected mem name") ||
3803  parseToken(FIRToken::colon, "expected ':' in mem") || parseOptionalInfo())
3804  return failure();
3805 
3806  FIRRTLType type;
3807  int64_t depth = -1, readLatency = -1, writeLatency = -1;
3808  RUWAttr ruw = RUWAttr::Undefined;
3809 
3810  SmallVector<std::pair<StringAttr, Type>, 4> ports;
3811 
3812  // Parse all the memfield records, which are indented more than the mem.
3813  while (1) {
3814  auto nextIndent = getIndentation();
3815  if (!nextIndent || *nextIndent <= memIndent)
3816  break;
3817 
3818  auto spelling = getTokenSpelling();
3819  if (parseToken(FIRToken::identifier, "unexpected token in 'mem'") ||
3820  parseToken(FIRToken::equal_greater, "expected '=>' in 'mem'"))
3821  return failure();
3822 
3823  if (spelling == "data-type") {
3824  if (type)
3825  return emitError("'mem' type specified multiple times"), failure();
3826 
3827  if (parseType(type, "expected type in data-type declaration"))
3828  return failure();
3829  continue;
3830  }
3831  if (spelling == "depth") {
3832  if (parseIntLit(depth, "expected integer in depth specification"))
3833  return failure();
3834  continue;
3835  }
3836  if (spelling == "read-latency") {
3837  if (parseIntLit(readLatency, "expected integer latency"))
3838  return failure();
3839  continue;
3840  }
3841  if (spelling == "write-latency") {
3842  if (parseIntLit(writeLatency, "expected integer latency"))
3843  return failure();
3844  continue;
3845  }
3846  if (spelling == "read-under-write") {
3847  if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
3848  FIRToken::kw_undefined))
3849  return emitError("expected specifier"), failure();
3850 
3851  if (parseOptionalRUW(ruw))
3852  return failure();
3853  continue;
3854  }
3855 
3856  MemOp::PortKind portKind;
3857  if (spelling == "reader")
3858  portKind = MemOp::PortKind::Read;
3859  else if (spelling == "writer")
3860  portKind = MemOp::PortKind::Write;
3861  else if (spelling == "readwriter")
3862  portKind = MemOp::PortKind::ReadWrite;
3863  else
3864  return emitError("unexpected field in 'mem' declaration"), failure();
3865 
3866  StringRef portName;
3867  if (parseId(portName, "expected port name"))
3868  return failure();
3869  auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
3870  if (!baseType)
3871  return emitError("unexpected type, must be base type");
3872  ports.push_back({builder.getStringAttr(portName),
3873  MemOp::getTypeForPort(depth, baseType, portKind)});
3874 
3875  while (!getIndentation().has_value()) {
3876  if (parseId(portName, "expected port name"))
3877  return failure();
3878  ports.push_back({builder.getStringAttr(portName),
3879  MemOp::getTypeForPort(depth, baseType, portKind)});
3880  }
3881  }
3882 
3883  // The FIRRTL dialect requires mems to have at least one port. Since portless
3884  // mems can never be referenced, it is always safe to drop them.
3885  if (ports.empty())
3886  return success();
3887 
3888  // Canonicalize the ports into alphabetical order.
3889  // TODO: Move this into MemOp construction/canonicalization.
3890  llvm::array_pod_sort(ports.begin(), ports.end(),
3891  [](const std::pair<StringAttr, Type> *lhs,
3892  const std::pair<StringAttr, Type> *rhs) -> int {
3893  return lhs->first.getValue().compare(
3894  rhs->first.getValue());
3895  });
3896 
3897  auto annotations = getConstants().emptyArrayAttr;
3898  SmallVector<Attribute, 4> resultNames;
3899  SmallVector<Type, 4> resultTypes;
3900  SmallVector<Attribute, 4> resultAnnotations;
3901  for (auto p : ports) {
3902  resultNames.push_back(p.first);
3903  resultTypes.push_back(p.second);
3904  resultAnnotations.push_back(annotations);
3905  }
3906 
3907  locationProcessor.setLoc(startTok.getLoc());
3908 
3909  auto result = builder.create<MemOp>(
3910  resultTypes, readLatency, writeLatency, depth, ruw,
3911  builder.getArrayAttr(resultNames), id, NameKindEnum::InterestingName,
3912  annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
3913  MemoryInitAttr(), StringAttr());
3914 
3915  UnbundledValueEntry unbundledValueEntry;
3916  unbundledValueEntry.reserve(result.getNumResults());
3917  for (size_t i = 0, e = result.getNumResults(); i != e; ++i)
3918  unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
3919 
3920  moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
3921  auto entryID = UnbundledID(moduleContext.unbundledValues.size());
3922  return moduleContext.addSymbolEntry(id, entryID, startTok.getLoc());
3923 }
3924 
3925 /// node ::= 'node' id '=' exp info?
3926 ParseResult FIRStmtParser::parseNode() {
3927  auto startTok = consumeToken(FIRToken::kw_node);
3928 
3929  // If this was actually the start of a connect or something else handle
3930  // that.
3931  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3932  return *isExpr;
3933 
3934  StringRef id;
3935  Value initializer;
3936  if (parseId(id, "expected node name") ||
3937  parseToken(FIRToken::equal, "expected '=' in node") ||
3938  parseExp(initializer, "expected expression for node") ||
3939  parseOptionalInfo())
3940  return failure();
3941 
3942  locationProcessor.setLoc(startTok.getLoc());
3943 
3944  // Error out in the following conditions:
3945  //
3946  // 1. Node type is Analog (at the top level)
3947  // 2. Node type is not passive under an optional outer flip
3948  // (analog field is okay)
3949  //
3950  // Note: (1) is more restictive than normal NodeOp verification, but
3951  // this is added to align with the SFC. (2) is less restrictive than
3952  // the SFC to accomodate for situations where the node is something
3953  // weird like a module output or an instance input.
3954  auto initializerType = type_cast<FIRRTLType>(initializer.getType());
3955  auto initializerBaseType =
3956  type_dyn_cast<FIRRTLBaseType>(initializer.getType());
3957  if (type_isa<AnalogType>(initializerType) ||
3958  !(initializerBaseType && initializerBaseType.isPassive())) {
3959  emitError(startTok.getLoc())
3960  << "Node cannot be analog and must be passive or passive under a flip "
3961  << initializer.getType();
3962  return failure();
3963  }
3964 
3965  auto annotations = getConstants().emptyArrayAttr;
3966  StringAttr sym = {};
3967 
3968  bool forceable =
3969  !!firrtl::detail::getForceableResultType(true, initializer.getType());
3970  auto result =
3971  builder.create<NodeOp>(initializer, id, NameKindEnum::InterestingName,
3972  annotations, sym, forceable);
3973  return moduleContext.addSymbolEntry(id, result.getResult(),
3974  startTok.getLoc());
3975 }
3976 
3977 /// wire ::= 'wire' id ':' type info?
3978 ParseResult FIRStmtParser::parseWire() {
3979  auto startTok = consumeToken(FIRToken::kw_wire);
3980 
3981  // If this was actually the start of a connect or something else handle
3982  // that.
3983  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3984  return *isExpr;
3985 
3986  StringRef id;
3987  FIRRTLType type;
3988  if (parseId(id, "expected wire name") ||
3989  parseToken(FIRToken::colon, "expected ':' in wire") ||
3990  parseType(type, "expected wire type") || parseOptionalInfo())
3991  return failure();
3992 
3993  locationProcessor.setLoc(startTok.getLoc());
3994 
3995  auto annotations = getConstants().emptyArrayAttr;
3996  StringAttr sym = {};
3997 
3998  bool forceable = !!firrtl::detail::getForceableResultType(true, type);
3999  // Names of only-nonHW should be droppable.
4000  auto namekind = isa<PropertyType, RefType>(type)
4001  ? NameKindEnum::DroppableName
4002  : NameKindEnum::InterestingName;
4003 
4004  auto result =
4005  builder.create<WireOp>(type, id, namekind, annotations, sym, forceable);
4006  return moduleContext.addSymbolEntry(id, result.getResult(),
4007  startTok.getLoc());
4008 }
4009 
4010 /// register ::= 'reg' id ':' type exp ('with' ':' reset_block)? info?
4011 ///
4012 /// reset_block ::= INDENT simple_reset info? NEWLINE DEDENT
4013 /// ::= '(' simple_reset ')'
4014 ///
4015 /// simple_reset ::= simple_reset0
4016 /// ::= '(' simple_reset0 ')'
4017 ///
4018 /// simple_reset0: 'reset' '=>' '(' exp exp ')'
4019 ///
4020 ParseResult FIRStmtParser::parseRegister(unsigned regIndent) {
4021  auto startTok = consumeToken(FIRToken::kw_reg);
4022 
4023  // If this was actually the start of a connect or something else handle
4024  // that.
4025  if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4026  return *isExpr;
4027 
4028  StringRef id;
4029  FIRRTLType type;
4030  Value clock;
4031 
4032  // TODO(firrtl spec): info? should come after the clock expression before
4033  // the 'with'.
4034  if (parseId(id, "expected reg name") ||
4035  parseToken(FIRToken::colon, "expected ':' in reg") ||
4036  parseType(type, "expected reg type") ||
4037  parseExp(clock, "expected expression for register clock"))
4038  return failure();
4039 
4040  if (!type_isa<FIRRTLBaseType>(type))
4041  return emitError(startTok.getLoc(), "register must have base type");
4042 
4043  // Parse the 'with' specifier if present.
4044  Value resetSignal, resetValue;
4045  if (consumeIf(FIRToken::kw_with)) {
4046  if (parseToken(FIRToken::colon, "expected ':' in reg"))
4047  return failure();
4048 
4049  // TODO(firrtl spec): Simplify the grammar for register reset logic.
4050  // Why allow multiple ambiguous parentheses? Why rely on indentation at
4051  // all?
4052 
4053  // This implements what the examples have in practice.
4054  bool hasExtraLParen = consumeIf(FIRToken::l_paren);
4055 
4056  auto indent = getIndentation();
4057  if (!indent || *indent <= regIndent)
4058  if (!hasExtraLParen)
4059  return emitError("expected indented reset specifier in reg"), failure();
4060 
4061  if (parseToken(FIRToken::kw_reset, "expected 'reset' in reg") ||
4062  parseToken(FIRToken::equal_greater, "expected => in reset specifier") ||
4063  parseToken(FIRToken::l_paren, "expected '(' in reset specifier") ||
4064  parseExp(resetSignal, "expected expression for reset signal"))
4065  return failure();
4066 
4067  // The Scala implementation of FIRRTL represents registers without resets
4068  // as a self referential register... and the pretty printer doesn't print
4069  // the right form. Recognize that this is happening and treat it as a
4070  // register without a reset for compatibility.
4071  // TODO(firrtl scala impl): pretty print registers without resets right.
4072  if (getTokenSpelling() == id) {
4073  consumeToken();
4074  if (parseToken(FIRToken::r_paren, "expected ')' in reset specifier"))
4075  return failure();
4076  resetSignal = Value();
4077  } else {
4078  if (parseExp(resetValue, "expected expression for reset value") ||
4079  parseToken(FIRToken::r_paren, "expected ')' in reset specifier"))
4080  return failure();
4081  }
4082 
4083  if (hasExtraLParen &&
4084  parseToken(FIRToken::r_paren, "expected ')' in reset specifier"))
4085  return failure();
4086  }
4087 
4088  // Finally, handle the last info if present, providing location info for the
4089  // clock expression.
4090  if (parseOptionalInfo())
4091  return failure();
4092 
4093  locationProcessor.setLoc(startTok.getLoc());
4094 
4095  ArrayAttr annotations = getConstants().emptyArrayAttr;
4096  Value result;
4097  StringAttr sym = {};
4098  bool forceable = !!firrtl::detail::getForceableResultType(true, type);
4099  if (resetSignal)
4100  result = builder
4101  .create<RegResetOp>(type, clock, resetSignal, resetValue, id,
4102  NameKindEnum::InterestingName, annotations,
4103  sym, forceable)
4104  .getResult();
4105  else
4106  result = builder
4107  .create<RegOp>(type, clock, id, NameKindEnum::InterestingName,
4108  annotations, sym, forceable)
4109  .getResult();
4110  return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
4111 }
4112 
4113 /// registerWithReset ::= 'regreset' id ':' type exp exp exp
4114 ///
4115 /// This syntax is only supported in FIRRTL versions >= 3.0.0. Because this
4116 /// syntax is only valid for >= 3.0.0, there is no need to check if the leading
4117 /// "regreset" is part of an expression with a leading keyword.
4118 ParseResult FIRStmtParser::parseRegisterWithReset() {
4119  auto startTok = consumeToken(FIRToken::kw_regreset);
4120 
4121  StringRef id;
4122  FIRRTLType type;
4123  Value clock, resetSignal, resetValue;
4124 
4125  if (parseId(id, "expected reg name") ||
4126  parseToken(FIRToken::colon, "expected ':' in reg") ||
4127  parseType(type, "expected reg type") ||
4128  parseExp(clock, "expected expression for register clock") ||
4129  parseExp(resetSignal, "expected expression for register reset") ||
4130  parseExp(resetValue, "expected expression for register reset value") ||
4131  parseOptionalInfo())
4132  return failure();
4133 
4134  if (!type_isa<FIRRTLBaseType>(type))
4135  return emitError(startTok.getLoc(), "register must have base type");
4136 
4137  locationProcessor.setLoc(startTok.getLoc());
4138 
4139  bool forceable = !!firrtl::detail::getForceableResultType(true, type);
4140  auto result = builder
4141  .create<RegResetOp>(type, clock, resetSignal, resetValue,
4142  id, NameKindEnum::InterestingName,
4143  getConstants().emptyArrayAttr,
4144  StringAttr{}, forceable)
4145  .getResult();
4146 
4147  return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
4148 }
4149 
4150 //===----------------------------------------------------------------------===//
4151 // FIRCircuitParser
4152 //===----------------------------------------------------------------------===//
4153 
4154 namespace {
4155 /// This class implements the outer level of the parser, including things
4156 /// like circuit and module.
4157 struct FIRCircuitParser : public FIRParser {
4158  explicit FIRCircuitParser(SharedParserConstants &state, FIRLexer &lexer,
4159  ModuleOp mlirModule, FIRVersion version)
4160  : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
4161 
4162  ParseResult
4163  parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
4164  SmallVectorImpl<const llvm::MemoryBuffer *> &omirBuf,
4165  mlir::TimingScope &ts);
4166 
4167 private:
4168  /// Extract Annotations from a JSON-encoded Annotation array string and add
4169  /// them to a vector of attributes.
4170  ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
4171  SmallVectorImpl<Attribute> &attrs);
4172  /// Generate OMIR-derived annotations. Report errors if the OMIR is malformed
4173  /// in any way. This also performs scattering of the OMIR to introduce
4174  /// tracking annotations in the circuit.
4175  ParseResult importOMIR(CircuitOp circuit, SMLoc loc, StringRef annotationStr,
4176  SmallVectorImpl<Attribute> &attrs);
4177 
4178  ParseResult parseToplevelDefinition(CircuitOp circuit, unsigned indent);
4179 
4180  ParseResult parseClass(CircuitOp circuit, unsigned indent);
4181  ParseResult parseExtClass(CircuitOp circuit, unsigned indent);
4182  ParseResult parseExtModule(CircuitOp circuit, unsigned indent);
4183  ParseResult parseIntModule(CircuitOp circuit, unsigned indent);
4184  ParseResult parseModule(CircuitOp circuit, unsigned indent);
4185 
4186  ParseResult parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
4187  SmallVectorImpl<SMLoc> &resultPortLocs,
4188  unsigned indent);
4189  ParseResult parseParameterList(ArrayAttr &resultParameters);
4190  ParseResult parseParameter(StringAttr &resultName, TypedAttr &resultValue,
4191  SMLoc &resultLoc);
4192  ParseResult parseRefList(ArrayRef<PortInfo> portList,
4193  ArrayAttr &internalPathResults);
4194 
4195  ParseResult skipToModuleEnd(unsigned indent);
4196 
4197  ParseResult parseTypeDecl();
4198 
4199  ParseResult parseGroupDecl(CircuitOp circuit);
4200 
4201  struct DeferredModuleToParse {
4202  FModuleLike moduleOp;
4203  SmallVector<SMLoc> portLocs;
4204  FIRLexerCursor lexerCursor;
4205  unsigned indent;
4206  };
4207 
4208  ParseResult parseModuleBody(DeferredModuleToParse &deferredModule);
4209 
4210  SmallVector<DeferredModuleToParse, 0> deferredModules;
4211  ModuleOp mlirModule;
4212 };
4213 
4214 } // end anonymous namespace
4215 ParseResult
4216 FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
4217  SmallVectorImpl<Attribute> &attrs) {
4218 
4219  auto annotations = json::parse(annotationsStr);
4220  if (auto err = annotations.takeError()) {
4221  handleAllErrors(std::move(err), [&](const json::ParseError &a) {
4222  auto diag = emitError(loc, "Failed to parse JSON Annotations");
4223  diag.attachNote() << a.message();
4224  });
4225  return failure();
4226  }
4227 
4228  json::Path::Root root;
4229  llvm::StringMap<ArrayAttr> thisAnnotationMap;
4230  if (!fromJSONRaw(annotations.get(), attrs, root, getContext())) {
4231  auto diag = emitError(loc, "Invalid/unsupported annotation format");
4232  std::string jsonErrorMessage =
4233  "See inline comments for problem area in JSON:\n";
4234  llvm::raw_string_ostream s(jsonErrorMessage);
4235  root.printErrorContext(annotations.get(), s);
4236  diag.attachNote() << jsonErrorMessage;
4237  return failure();
4238  }
4239 
4240  return success();
4241 }
4242 
4243 ParseResult FIRCircuitParser::importOMIR(CircuitOp circuit, SMLoc loc,
4244  StringRef annotationsStr,
4245  SmallVectorImpl<Attribute> &annos) {
4246 
4247  auto annotations = json::parse(annotationsStr);
4248  if (auto err = annotations.takeError()) {
4249  handleAllErrors(std::move(err), [&](const json::ParseError &a) {
4250  auto diag = emitError(loc, "Failed to parse OMIR file");
4251  diag.attachNote() << a.message();
4252  });
4253  return failure();
4254  }
4255 
4256  json::Path::Root root;
4257  if (!fromOMIRJSON(annotations.get(), annos, root, circuit.getContext())) {
4258  auto diag = emitError(loc, "Invalid/unsupported OMIR format");
4259  std::string jsonErrorMessage =
4260  "See inline comments for problem area in JSON:\n";
4261  llvm::raw_string_ostream s(jsonErrorMessage);
4262  root.printErrorContext(annotations.get(), s);
4263  diag.attachNote() << jsonErrorMessage;
4264  return failure();
4265  }
4266 
4267  return success();
4268 }
4269 
4270 /// portlist ::= port*
4271 /// port ::= dir id ':' type info? NEWLINE
4272 /// dir ::= 'input' | 'output'
4273 ParseResult
4274 FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
4275  SmallVectorImpl<SMLoc> &resultPortLocs,
4276  unsigned indent) {
4277  // Parse any ports.
4278  while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
4279  // Must be nested under the module.
4280  getIndentation() > indent) {
4281 
4282  // We need one token lookahead to resolve the ambiguity between:
4283  // output foo ; port
4284  // output <= input ; identifier expression
4285  // output.thing <= input ; identifier expression
4286  auto backtrackState = getLexer().getCursor();
4287 
4288  bool isOutput = getToken().is(FIRToken::kw_output);
4289  consumeToken();
4290 
4291  // If we have something that isn't a keyword then this must be an
4292  // identifier, not an input/output marker.
4293  if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
4294  !getToken().isKeyword()) {
4295  backtrackState.restore(getLexer());
4296  break;
4297  }
4298 
4299  StringAttr name;
4300  FIRRTLType type;
4301  LocWithInfo info(getToken().getLoc(), this);
4302  if (parseId(name, "expected port name") ||
4303  parseToken(FIRToken::colon, "expected ':' in port definition") ||
4304  parseType(type, "expected a type in port declaration") ||
4305  info.parseOptionalInfo())
4306  return failure();
4307 
4308  StringAttr innerSym = {};
4309  resultPorts.push_back(
4310  {name, type, direction::get(isOutput), innerSym, info.getLoc()});
4311  resultPortLocs.push_back(info.getFIRLoc());
4312  }
4313 
4314  // Helper for the temporary check rejecting input-oriented refs.
4315  std::function<bool(Type, bool)> hasInputRef = [&](Type type,
4316  bool output) -> bool {
4317  auto ftype = type_dyn_cast<FIRRTLType>(type);
4318  if (!ftype || !ftype.containsReference())
4319  return false;
4320  return TypeSwitch<FIRRTLType, bool>(ftype)
4321  .Case<RefType>([&](auto reftype) { return !output; })
4322  .Case<OpenVectorType>([&](OpenVectorType ovt) {
4323  return hasInputRef(ovt.getElementType(), output);
4324  })
4325  .Case<OpenBundleType>([&](OpenBundleType obt) {
4326  for (auto field : obt.getElements())
4327  if (hasInputRef(field.type, field.isFlip ^ output))
4328  return true;
4329  return false;
4330  });
4331  };
4332 
4333  // Check for port name collisions.
4335  for (auto portAndLoc : llvm::zip(resultPorts, resultPortLocs)) {
4336  PortInfo &port = std::get<0>(portAndLoc);
4337  // See #4812 and look through the reference input test collection
4338  // and ensure they work before allowing them from user input.
4339  if (hasInputRef(port.type, port.isOutput()))
4340  return emitError(std::get<1>(portAndLoc),
4341  "input probes not yet supported");
4342  auto &entry = portIds[port.name];
4343  if (!entry.isValid()) {
4344  entry = std::get<1>(portAndLoc);
4345  continue;
4346  }
4347 
4348  emitError(std::get<1>(portAndLoc),
4349  "redefinition of name '" + port.getName() + "'")
4350  .attachNote(translateLocation(entry))
4351  << "previous definition here";
4352  return failure();
4353  }
4354 
4355  return success();
4356 }
4357 
4358 /// ref-list ::= ref*
4359 /// ref ::= 'ref' static_reference 'is' StringLit NEWLIN
4360 ParseResult FIRCircuitParser::parseRefList(ArrayRef<PortInfo> portList,
4361  ArrayAttr &internalPathsResult) {
4362  struct RefStatementInfo {
4363  StringAttr refName;
4364  InternalPathAttr resolvedPath;
4365  SMLoc loc;
4366  };
4367 
4368  SmallVector<RefStatementInfo> refStatements;
4369  SmallPtrSet<StringAttr, 8> seenNames;
4370  SmallPtrSet<StringAttr, 8> seenRefs;
4371 
4372  // Parse the ref statements.
4373  while (consumeIf(FIRToken::kw_ref)) {
4374  auto loc = getToken().getLoc();
4375  // ref x is "a.b.c"
4376  // Support "ref x.y is " once aggregate-of-ref supported.
4377  StringAttr refName;
4378  if (parseId(refName, "expected ref name"))
4379  return failure();
4380  if (consumeIf(FIRToken::period) || consumeIf(FIRToken::l_square))
4381  return emitError(
4382  loc, "ref statements for aggregate elements not yet supported");
4383  if (parseToken(FIRToken::kw_is, "expected 'is' in ref statement"))
4384  return failure();
4385 
4386  if (!seenRefs.insert(refName).second)
4387  return emitError(loc, "duplicate ref statement for '" + refName.strref() +
4388  "'");
4389 
4390  auto kind = getToken().getKind();
4391  if (kind != FIRToken::string)
4392  return emitError(loc, "expected string in ref statement");
4393  auto resolved = InternalPathAttr::get(
4394  getContext(),
4395  StringAttr::get(getContext(), getToken().getStringValue()));
4396  consumeToken(FIRToken::string);
4397 
4398  refStatements.push_back(RefStatementInfo{refName, resolved, loc});
4399  }
4400 
4401  // Build paths array. One entry for each ref-type port, empty for others.
4402  SmallVector<Attribute> internalPaths(portList.size(),
4403  InternalPathAttr::get(getContext()));
4404 
4405  llvm::SmallBitVector usedRefs(refStatements.size());
4406  size_t matchedPaths = 0;
4407  for (auto [idx, port] : llvm::enumerate(portList)) {
4408  if (!type_isa<RefType>(port.type))
4409  continue;
4410 
4411  // Reject input reftype ports on extmodule's per spec,
4412  // as well as on intmodule's which is not mentioned in spec.
4413  if (!port.isOutput())
4414  return mlir::emitError(
4415  port.loc,
4416  "references in ports must be output on extmodule and intmodule");
4417  auto *refStmtIt =
4418  llvm::find_if(refStatements, [pname = port.name](const auto &r) {
4419  return r.refName == pname;
4420  });
4421  // Error if ref statements are present but none found for this port.
4422  if (refStmtIt == refStatements.end()) {
4423  if (!refStatements.empty())
4424  return mlir::emitError(port.loc, "no ref statement found for ref port ")
4425  .append(port.name);
4426  continue;
4427  }
4428 
4429  usedRefs.set(std::distance(refStatements.begin(), refStmtIt));
4430  internalPaths[idx] = refStmtIt->resolvedPath;
4431  ++matchedPaths;
4432  }
4433 
4434  if (!refStatements.empty() && matchedPaths != refStatements.size()) {
4435  assert(matchedPaths < refStatements.size());
4436  assert(!usedRefs.all());
4437  auto idx = usedRefs.find_first_unset();
4438  assert(idx != -1);
4439  return emitError(refStatements[idx].loc, "unused ref statement");
4440  }
4441 
4442  if (matchedPaths)
4443  internalPathsResult = ArrayAttr::get(getContext(), internalPaths);
4444  return success();
4445 }
4446 
4447 /// We're going to defer parsing this module, so just skip tokens until we
4448 /// get to the next module or the end of the file.
4449 ParseResult FIRCircuitParser::skipToModuleEnd(unsigned indent) {
4450  while (true) {
4451  switch (getToken().getKind()) {
4452 
4453  // End of file or invalid token will be handled by outer level.
4454  case FIRToken::eof:
4455  case FIRToken::error:
4456  return success();
4457 
4458  // If we got to the next top-level declaration, then we're done.
4459  case FIRToken::kw_class:
4460  case FIRToken::kw_declgroup:
4461  case FIRToken::kw_extclass:
4462  case FIRToken::kw_extmodule:
4463  case FIRToken::kw_intmodule:
4464  case FIRToken::kw_module:
4465  case FIRToken::kw_type:
4466  // All module declarations should have the same indentation
4467  // level. Use this fact to differentiate between module
4468  // declarations and usages of "module" as identifiers.
4469  if (getIndentation() == indent)
4470  return success();
4471  [[fallthrough]];
4472  default:
4473  consumeToken();
4474  break;
4475  }
4476  }
4477 }
4478 
4479 /// parameter ::= 'parameter' id '=' intLit NEWLINE
4480 /// parameter ::= 'parameter' id '=' StringLit NEWLINE
4481 /// parameter ::= 'parameter' id '=' floatingpoint NEWLINE
4482 /// parameter ::= 'parameter' id '=' VerbatimStringLit NEWLINE
4483 ParseResult FIRCircuitParser::parseParameter(StringAttr &resultName,
4484  TypedAttr &resultValue,
4485  SMLoc &resultLoc) {
4486  mlir::Builder builder(getContext());
4487 
4488  consumeToken(FIRToken::kw_parameter);
4489  auto loc = getToken().getLoc();
4490 
4491  StringRef name;
4492  if (parseId(name, "expected parameter name") ||
4493  parseToken(FIRToken::equal, "expected '=' in parameter"))
4494  return failure();
4495 
4496  TypedAttr value;
4497  switch (getToken().getKind()) {
4498  default:
4499  return emitError("expected parameter value"), failure();
4500  case FIRToken::integer:
4501  case FIRToken::signed_integer: {
4502  APInt result;
4503  if (parseIntLit(result, "invalid integer parameter"))
4504  return failure();
4505 
4506  // If the integer parameter is less than 32-bits, sign extend this to a
4507  // 32-bit value. This needs to eventually emit as a 32-bit value in
4508  // Verilog and we want to get the size correct immediately.
4509  if (result.getBitWidth() < 32)
4510  result = result.sext(32);
4511 
4512  value = builder.getIntegerAttr(
4513  builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
4514  result);
4515  break;
4516  }
4517  case FIRToken::string: {
4518  // Drop the double quotes and unescape.
4519  value = builder.getStringAttr(getToken().getStringValue());
4520  consumeToken(FIRToken::string);
4521  break;
4522  }
4523  case FIRToken::verbatim_string: {
4524  // Drop the single quotes and unescape the ones inside.
4525  auto text = builder.getStringAttr(getToken().getVerbatimStringValue());
4526  value = hw::ParamVerbatimAttr::get(text);
4527  consumeToken(FIRToken::verbatim_string);
4528  break;
4529  }
4530  case FIRToken::floatingpoint:
4531  double v;
4532  if (!llvm::to_float(getTokenSpelling(), v))
4533  return emitError("invalid float parameter syntax"), failure();
4534 
4535  value = builder.getF64FloatAttr(v);
4536  consumeToken(FIRToken::floatingpoint);
4537  break;
4538  }
4539 
4540  resultName = builder.getStringAttr(name);
4541  resultValue = value;
4542  resultLoc = loc;
4543  return success();
4544 }
4545 
4546 /// parameter-list ::= parameter*
4547 ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
4548  SmallVector<Attribute, 8> parameters;
4549  SmallPtrSet<StringAttr, 8> seen;
4550  while (getToken().is(FIRToken::kw_parameter)) {
4551  StringAttr name;
4552  TypedAttr value;
4553  SMLoc loc;
4554  if (parseParameter(name, value, loc))
4555  return failure();
4556  if (!seen.insert(name).second)
4557  return emitError(loc,
4558  "redefinition of parameter '" + name.getValue() + "'");
4559  parameters.push_back(ParamDeclAttr::get(name, value));
4560  }
4561  resultParameters = ArrayAttr::get(getContext(), parameters);
4562  return success();
4563 }
4564 
4565 /// class ::= 'class' id ':' info? INDENT portlist simple_stmt_block DEDENT
4566 ParseResult FIRCircuitParser::parseClass(CircuitOp circuit, unsigned indent) {
4567  StringAttr name;
4568  SmallVector<PortInfo, 8> portList;
4569  SmallVector<SMLoc> portLocs;
4570  LocWithInfo info(getToken().getLoc(), this);
4571 
4572  if (requireFeature({3, 2, 0}, "classes"))
4573  return failure();
4574 
4575  consumeToken(FIRToken::kw_class);
4576  if (parseId(name, "expected class name") ||
4577  parseToken(FIRToken::colon, "expected ':' in class definition") ||
4578  info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
4579  return failure();
4580 
4581  if (name == circuit.getName())
4582  return mlir::emitError(info.getLoc(),
4583  "class cannot be the top of a circuit");
4584 
4585  for (auto &portInfo : portList)
4586  if (!isa<PropertyType>(portInfo.type))
4587  return mlir::emitError(portInfo.loc,
4588  "ports on classes must be properties");
4589 
4590  // build it
4591  auto builder = circuit.getBodyBuilder();
4592  auto classOp = builder.create<ClassOp>(info.getLoc(), name, portList);
4593  deferredModules.emplace_back(
4594  DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
4595 
4596  // Stash the class name -> op in the constants, so we can resolve Inst types.
4597  getConstants().classMap[name.getValue()] = classOp;
4598  return skipToModuleEnd(indent);
4599 }
4600 
4601 /// extclass ::= 'extclass' id ':' info? INDENT portlist DEDENT
4602 ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
4603  unsigned indent) {
4604  StringAttr name;
4605  SmallVector<PortInfo, 8> portList;
4606  SmallVector<SMLoc> portLocs;
4607  LocWithInfo info(getToken().getLoc(), this);
4608 
4609  if (requireFeature({3, 2, 0}, "classes"))
4610  return failure();
4611 
4612  consumeToken(FIRToken::kw_extclass);
4613  if (parseId(name, "expected extclass name") ||
4614  parseToken(FIRToken::colon, "expected ':' in extclass definition") ||
4615  info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
4616  return failure();
4617 
4618  if (name == circuit.getName())
4619  return mlir::emitError(info.getLoc(),
4620  "extclass cannot be the top of a circuit");
4621 
4622  for (auto &portInfo : portList)
4623  if (!isa<PropertyType>(portInfo.type))
4624  return mlir::emitError(portInfo.loc,
4625  "ports on extclasses must be properties");
4626 
4627  // Build it
4628  auto builder = circuit.getBodyBuilder();
4629  auto extClassOp = builder.create<ExtClassOp>(info.getLoc(), name, portList);
4630 
4631  // Stash the class name -> op in the constants, so we can resolve Inst types.
4632  getConstants().classMap[name.getValue()] = extClassOp;
4633  return skipToModuleEnd(indent);
4634 }
4635 
4636 /// extmodule ::=
4637 /// 'extmodule' id ':' info?
4638 /// INDENT portlist defname? parameter-list ref-list DEDENT
4639 /// defname ::= 'defname' '=' id NEWLINE
4640 ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
4641  unsigned indent) {
4642  StringAttr name;
4643  SmallVector<PortInfo, 8> portList;
4644  SmallVector<SMLoc> portLocs;
4645  LocWithInfo info(getToken().getLoc(), this);
4646  consumeToken(FIRToken::kw_extmodule);
4647  if (parseId(name, "expected extmodule name") ||
4648  parseToken(FIRToken::colon, "expected ':' in extmodule definition") ||
4649  info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
4650  return failure();
4651 
4652  StringRef defName;
4653  if (consumeIf(FIRToken::kw_defname)) {
4654  if (parseToken(FIRToken::equal, "expected '=' in defname") ||
4655  parseId(defName, "expected defname name"))
4656  return failure();
4657  }
4658 
4659  ArrayAttr parameters;
4660  ArrayAttr internalPaths;
4661  if (parseParameterList(parameters) || parseRefList(portList, internalPaths))
4662  return failure();
4663 
4664  auto builder = circuit.getBodyBuilder();
4665  auto convention = getConstants().options.scalarizeExtModules
4666  ? Convention::Scalarized
4667  : Convention::Internal;
4668  auto conventionAttr = ConventionAttr::get(getContext(), convention);
4669  auto annotations = ArrayAttr::get(getContext(), {});
4670  builder.create<FExtModuleOp>(info.getLoc(), name, conventionAttr, portList,
4671  defName, annotations, parameters, internalPaths);
4672  return success();
4673 }
4674 
4675 /// intmodule ::=
4676 /// 'intmodule' id ':' info?
4677 /// INDENT portlist intname parameter-list ref-list DEDENT
4678 /// intname ::= 'intrinsic' '=' id NEWLINE
4679 ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
4680  unsigned indent) {
4681  StringAttr name;
4682  SmallVector<PortInfo, 8> portList;
4683  SmallVector<SMLoc> portLocs;
4684  LocWithInfo info(getToken().getLoc(), this);
4685  consumeToken(FIRToken::kw_intmodule);
4686  if (parseId(name, "expected intmodule name") ||
4687  parseToken(FIRToken::colon, "expected ':' in intmodule definition") ||
4688  info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
4689  return failure();
4690 
4691  StringRef intName;
4692  if (consumeIf(FIRToken::kw_intrinsic)) {
4693  if (parseToken(FIRToken::equal, "expected '=' in intrinsic") ||
4694  parseId(intName, "expected intrinsic name"))
4695  return failure();
4696  }
4697 
4698  ArrayAttr parameters;
4699  ArrayAttr internalPaths;
4700  if (parseParameterList(parameters) || parseRefList(portList, internalPaths))
4701  return failure();
4702 
4703  ArrayAttr annotations = getConstants().emptyArrayAttr;
4704  auto builder = circuit.getBodyBuilder();
4705  builder.create<FIntModuleOp>(info.getLoc(), name, portList, intName,
4706  annotations, parameters, internalPaths);
4707  return success();
4708 }
4709 
4710 /// module ::= 'module' id ':' info? INDENT portlist simple_stmt_block DEDENT
4711 ParseResult FIRCircuitParser::parseModule(CircuitOp circuit, unsigned indent) {
4712  StringAttr name;
4713  SmallVector<PortInfo, 8> portList;
4714  SmallVector<SMLoc> portLocs;
4715  LocWithInfo info(getToken().getLoc(), this);
4716  consumeToken(FIRToken::kw_module);
4717  if (parseId(name, "expected module name") ||
4718  parseToken(FIRToken::colon, "expected ':' in module definition") ||
4719  info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
4720  return failure();
4721 
4722  auto circuitName = circuit.getName();
4723  auto isMainModule = (name == circuitName);
4724  ArrayAttr annotations = getConstants().emptyArrayAttr;
4725  auto convention = Convention::Internal;
4726  if (isMainModule && getConstants().options.scalarizeTopModule)
4727  convention = Convention::Scalarized;
4728  auto conventionAttr = ConventionAttr::get(getContext(), convention);
4729  auto builder = circuit.getBodyBuilder();
4730  auto moduleOp = builder.create<FModuleOp>(info.getLoc(), name, conventionAttr,
4731  portList, annotations);
4732  auto visibility = isMainModule ? SymbolTable::Visibility::Public
4733  : SymbolTable::Visibility::Private;
4734  SymbolTable::setSymbolVisibility(moduleOp, visibility);
4735 
4736  // Parse the body of this module after all prototypes have been parsed. This
4737  // allows us to handle forward references correctly.
4738  deferredModules.emplace_back(DeferredModuleToParse{
4739  moduleOp, portLocs, getLexer().getCursor(), indent});
4740 
4741  if (skipToModuleEnd(indent))
4742  return failure();
4743  return success();
4744 }
4745 
4746 ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
4747  unsigned indent) {
4748  switch (getToken().getKind()) {
4749  case FIRToken::kw_class:
4750  return parseClass(circuit, indent);
4751  case FIRToken::kw_declgroup:
4752  if (requireFeature({3, 1, 0}, "optional groups"))
4753  return failure();
4754  return parseGroupDecl(circuit);
4755  case FIRToken::kw_extclass:
4756  return parseExtClass(circuit, indent);
4757  case FIRToken::kw_extmodule:
4758  return parseExtModule(circuit, indent);
4759  case FIRToken::kw_intmodule:
4760  return parseIntModule(circuit, indent);
4761  case FIRToken::kw_module:
4762  return parseModule(circuit, indent);
4763  case FIRToken::kw_type:
4764  return parseTypeDecl();
4765  default:
4766  return emitError(getToken().getLoc(), "unknown toplevel definition");
4767  }
4768 }
4769 
4770 // Parse a type declaration.
4771 ParseResult FIRCircuitParser::parseTypeDecl() {
4772  StringRef id;
4773  FIRRTLType type;
4774  consumeToken();
4775  auto loc = getToken().getLoc();
4776 
4777  if (getToken().isKeyword())
4778  return emitError(loc) << "cannot use keyword '" << getToken().getSpelling()
4779  << "' for type alias name";
4780 
4781  if (parseId(id, "expected type name") ||
4782  parseToken(FIRToken::equal, "expected '=' in type decl") ||
4783  parseType(type, "expected a type"))
4784  return failure();
4785  auto name = StringAttr::get(type.getContext(), id);
4786  // Create type alias only for base types. Otherwise just pass through the
4787  // type.
4788  if (auto base = type_dyn_cast<FIRRTLBaseType>(type))
4789  type = BaseTypeAliasType::get(name, base);
4790  else
4791  emitWarning(loc)
4792  << "type alias for non-base type " << type
4793  << " is currently not supported. Type alias is stripped immediately";
4794 
4795  if (!getConstants().aliasMap.insert({id, type}).second)
4796  return emitError(loc) << "type alias `" << name.getValue()
4797  << "` is already defined";
4798  return success();
4799 }
4800 
4801 // Parse a group declaration.
4802 ParseResult FIRCircuitParser::parseGroupDecl(CircuitOp circuit) {
4803  auto baseIndent = getIndentation();
4804 
4805  // A stack of all groups that are possibly parents of the current group.
4806  SmallVector<std::pair<std::optional<unsigned>, GroupDeclOp>> groupStack;
4807 
4808  // Parse a single group and add it to the groupStack.
4809  auto parseOne = [&](Block *block) -> ParseResult {
4810  auto indent = getIndentation();
4811  StringRef id, convention;
4812  LocWithInfo info(getToken().getLoc(), this);
4813  consumeToken();
4814  if (parseId(id, "expected group name") || parseGetSpelling(convention))
4815  return failure();
4816  auto groupConvention = symbolizeGroupConvention(convention);
4817  if (!groupConvention) {
4818  emitError() << "unknown convention '" << convention
4819  << "' (did you misspell it?)";
4820  return failure();
4821  }
4822  consumeToken();
4823  if (parseToken(FIRToken::colon, "expected ':' after group definition") ||
4824  info.parseOptionalInfo())
4825  return failure();
4826  auto builder = OpBuilder::atBlockEnd(block);
4827  // Create the group declaration and give it an empty block.
4828  auto groupDeclOp =
4829  builder.create<GroupDeclOp>(info.getLoc(), id, *groupConvention);
4830  groupDeclOp->getRegion(0).push_back(new Block());
4831  groupStack.push_back({indent, groupDeclOp});
4832  return success();
4833  };
4834 
4835  if (parseOne(circuit.getBodyBlock()))
4836  return failure();
4837 
4838  // Parse any nested groups.
4839  while (getIndentation() > baseIndent) {
4840  switch (getToken().getKind()) {
4841  case FIRToken::kw_declgroup: {
4842  // Pop nested groups off the stack until we find out what group to insert
4843  // this into.
4844  while (groupStack.back().first >= getIndentation())
4845  groupStack.pop_back();
4846  auto parentGroup = groupStack.back().second;
4847  if (parseOne(&parentGroup.getBody().front()))
4848  return failure();
4849  break;
4850  }
4851  default:
4852  return emitError("expected 'declgroup'"), failure();
4853  }
4854  }
4855 
4856  return success();
4857 }
4858 
4859 // Parse the body of this module.
4860 ParseResult
4861 FIRCircuitParser::parseModuleBody(DeferredModuleToParse &deferredModule) {
4862  FModuleLike moduleOp = deferredModule.moduleOp;
4863  auto &body = moduleOp->getRegion(0).front();
4864  auto &portLocs = deferredModule.portLocs;
4865 
4866  // We parse the body of this module with its own lexer, enabling parallel
4867  // parsing with the rest of the other module bodies.
4868  FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
4869 
4870  // Reset the parser/lexer state back to right after the port list.
4871  deferredModule.lexerCursor.restore(moduleBodyLexer);
4872 
4873  FIRModuleContext moduleContext(getConstants(), moduleBodyLexer, version);
4874 
4875  // Install all of the ports into the symbol table, associated with their
4876  // block arguments.
4877  auto portList = moduleOp.getPorts();
4878  auto portArgs = body.getArguments();
4879  for (auto tuple : llvm::zip(portList, portLocs, portArgs)) {
4880  PortInfo &port = std::get<0>(tuple);
4881  llvm::SMLoc loc = std::get<1>(tuple);
4882  BlockArgument portArg = std::get<2>(tuple);
4883  assert(!port.sym);
4884  if (moduleContext.addSymbolEntry(port.getName(), portArg, loc))
4885  return failure();
4886  }
4887 
4888  hw::InnerSymbolNamespace modNameSpace(moduleOp);
4889  FIRStmtParser stmtParser(body, moduleContext, modNameSpace, version);
4890 
4891  // Parse the moduleBlock.
4892  auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
4893  if (failed(result))
4894  return result;
4895 
4896  // Convert print-encoded verifications after parsing.
4897 
4898  // It is dangerous to modify IR in the walk, so accumulate printFOp to
4899  // buffer.
4900  SmallVector<PrintFOp> buffer;
4901  deferredModule.moduleOp.walk(
4902  [&buffer](PrintFOp printFOp) { buffer.push_back(printFOp); });
4903 
4904  for (auto printFOp : buffer) {
4905  auto result = circt::firrtl::foldWhenEncodedVerifOp(printFOp);
4906  if (failed(result))
4907  return result;
4908  }
4909 
4910  // Demote any forceable operations that aren't being forced.
4911  deferredModule.moduleOp.walk([](Forceable fop) {
4912  if (fop.isForceable() && fop.getDataRef().use_empty())
4914  });
4915 
4916  return success();
4917 }
4918 
4919 /// file ::= circuit
4920 /// versionHeader ::= 'FIRRTL' 'version' versionLit NEWLINE
4921 /// circuit ::= versionHeader? 'circuit' id ':' info? INDENT module* DEDENT EOF
4922 ///
4923 /// If non-null, annotationsBuf is a memory buffer containing JSON annotations.
4924 /// If non-null, omirBufs is a vector of memory buffers containing SiFive Object
4925 /// Model IR (which is JSON).
4926 ///
4927 ParseResult FIRCircuitParser::parseCircuit(
4928  SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
4929  SmallVectorImpl<const llvm::MemoryBuffer *> &omirBufs,
4930  mlir::TimingScope &ts) {
4931 
4932  auto indent = getIndentation();
4933  if (consumeIf(FIRToken::kw_FIRRTL)) {
4934  if (!indent.has_value())
4935  return emitError("'FIRRTL' must be first token on its line"), failure();
4936  if (parseToken(FIRToken::kw_version, "expected version after 'FIRRTL'") ||
4937  parseVersionLit("expected version literal"))
4938  return failure();
4939  indent = getIndentation();
4940  }
4941 
4942  if (!indent.has_value())
4943  return emitError("'circuit' must be first token on its line"), failure();
4944  unsigned circuitIndent = *indent;
4945 
4946  LocWithInfo info(getToken().getLoc(), this);
4947  StringAttr name;
4948  SMLoc inlineAnnotationsLoc;
4949  StringRef inlineAnnotations;
4950 
4951  // A file must contain a top level `circuit` definition.
4952  if (parseToken(FIRToken::kw_circuit,
4953  "expected a top-level 'circuit' definition") ||
4954  parseId(name, "expected circuit name") ||
4955  parseToken(FIRToken::colon, "expected ':' in circuit definition") ||
4956  parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
4957  info.parseOptionalInfo())
4958  return failure();
4959 
4960  // Create the top-level circuit op in the MLIR module.
4961  OpBuilder b(mlirModule.getBodyRegion());
4962  auto circuit = b.create<CircuitOp>(info.getLoc(), name);
4963 
4964  // A timer to get execution time of annotation parsing.
4965  auto parseAnnotationTimer = ts.nest("Parse annotations");
4966 
4967  // Deal with any inline annotations, if they exist. These are processed
4968  // first to place any annotations from an annotation file *after* the inline
4969  // annotations. While arbitrary, this makes the annotation file have
4970  // "append" semantics.
4971  SmallVector<Attribute> annos;
4972  if (!inlineAnnotations.empty())
4973  if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
4974  return failure();
4975 
4976  // Deal with the annotation file if one was specified
4977  for (auto *annotationsBuf : annotationsBufs)
4978  if (importAnnotationsRaw(info.getFIRLoc(), annotationsBuf->getBuffer(),
4979  annos))
4980  return failure();
4981 
4982  parseAnnotationTimer.stop();
4983  auto parseOMIRTimer = ts.nest("Parse OMIR");
4984 
4985  // Process OMIR files as annotations with a class of
4986  // "freechips.rocketchip.objectmodel.OMNode"
4987  for (auto *omirBuf : omirBufs)
4988  if (importOMIR(circuit, info.getFIRLoc(), omirBuf->getBuffer(), annos))
4989  return failure();
4990 
4991  parseOMIRTimer.stop();
4992 
4993  // Get annotations that are supposed to be specially handled by the
4994  // LowerAnnotations pass.
4995  if (!annos.empty())
4996  circuit->setAttr(rawAnnotations, b.getArrayAttr(annos));
4997 
4998  // A timer to get execution time of module parsing.
4999  auto parseTimer = ts.nest("Parse modules");
5000  deferredModules.reserve(16);
5001 
5002  // Parse any contained modules.
5003  while (true) {
5004  switch (getToken().getKind()) {
5005  // If we got to the end of the file, then we're done.
5006  case FIRToken::eof:
5007  goto DoneParsing;
5008 
5009  // If we got an error token, then the lexer already emitted an error,
5010  // just stop. We could introduce error recovery if there was demand for
5011  // it.
5012  case FIRToken::error:
5013  return failure();
5014 
5015  default:
5016  emitError("unexpected token in circuit");
5017  return failure();
5018 
5019  case FIRToken::kw_class:
5020  case FIRToken::kw_declgroup:
5021  case FIRToken::kw_extclass:
5022  case FIRToken::kw_extmodule:
5023  case FIRToken::kw_intmodule:
5024  case FIRToken::kw_module:
5025  case FIRToken::kw_type: {
5026  auto indent = getIndentation();
5027  if (!indent.has_value())
5028  return emitError("'module' must be first token on its line"), failure();
5029  unsigned definitionIndent = *indent;
5030 
5031  if (definitionIndent <= circuitIndent)
5032  return emitError("module should be indented more"), failure();
5033 
5034  if (parseToplevelDefinition(circuit, definitionIndent))
5035  return failure();
5036  break;
5037  }
5038  }
5039  }
5040 
5041  // After the outline of the file has been parsed, we can go ahead and parse
5042  // all the bodies. This allows us to resolve forward-referenced modules and
5043  // makes it possible to parse their bodies in parallel.
5044 DoneParsing:
5045  // Each of the modules may translate source locations, and doing so touches
5046  // the SourceMgr to build a line number cache. This isn't thread safe, so we
5047  // proactively touch it to make sure that it is always already created.
5048  (void)getLexer().translateLocation(info.getFIRLoc());
5049 
5050  // Next, parse all the module bodies.
5051  auto anyFailed = mlir::failableParallelForEachN(
5052  getContext(), 0, deferredModules.size(), [&](size_t index) {
5053  if (parseModuleBody(deferredModules[index]))
5054  return failure();
5055  return success();
5056  });
5057  if (failed(anyFailed))
5058  return failure();
5059 
5060  auto main = circuit.getMainModule();
5061  if (!main) {
5062  // Give more specific error if no modules defined at all
5063  if (circuit.getOps<FModuleLike>().empty()) {
5064  return mlir::emitError(circuit.getLoc())
5065  << "no modules found, circuit must contain one or more modules";
5066  }
5067  if (auto *notModule = circuit.lookupSymbol(circuit.getName())) {
5068  return notModule->emitOpError()
5069  << "cannot have the same name as the circuit";
5070  }
5071  return mlir::emitError(circuit.getLoc())
5072  << "no main module found, circuit '" << circuit.getName()
5073  << "' must contain a module named '" << circuit.getName() << "'";
5074  }
5075 
5076  // If the circuit has an entry point that is not an external module, set the
5077  // visibility of all non-main modules to private.
5078  if (auto mainMod = dyn_cast<FModuleOp>(*main)) {
5079  for (auto mod : circuit.getOps<FModuleLike>()) {
5080  if (mod != main)
5081  SymbolTable::setSymbolVisibility(mod, SymbolTable::Visibility::Private);
5082  }
5083  // Reject if main module has input ref-type ports.
5084  // This should be checked in verifier for all public FModuleLike's but
5085  // they're used internally so check this here.
5086  for (auto &pi : mainMod.getPorts()) {
5087  if (!pi.isOutput() && type_isa<RefType>(pi.type))
5088  return mlir::emitError(pi.loc)
5089  << "main module may not contain input references";
5090  }
5091  }
5092  return success();
5093 }
5094 
5095 //===----------------------------------------------------------------------===//
5096 // Driver
5097 //===----------------------------------------------------------------------===//
5098 
5099 // Parse the specified .fir file into the specified MLIR context.
5101 circt::firrtl::importFIRFile(SourceMgr &sourceMgr, MLIRContext *context,
5102  mlir::TimingScope &ts, FIRParserOptions options) {
5103  auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
5104  SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
5105  unsigned fileID = 1;
5106  for (unsigned e = options.numAnnotationFiles + 1; fileID < e; ++fileID)
5107  annotationsBufs.push_back(
5108  sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
5109 
5110  SmallVector<const llvm::MemoryBuffer *> omirBufs;
5111  for (unsigned e = sourceMgr.getNumBuffers(); fileID < e; ++fileID)
5112  omirBufs.push_back(
5113  sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
5114 
5115  context->loadDialect<CHIRRTLDialect>();
5116  context->loadDialect<FIRRTLDialect, hw::HWDialect>();
5117 
5118  // This is the result module we are parsing into.
5119  mlir::OwningOpRef<mlir::ModuleOp> module(ModuleOp::create(
5120  FileLineColLoc::get(context, sourceBuf->getBufferIdentifier(), /*line=*/0,
5121  /*column=*/0)));
5122  SharedParserConstants state(context, options);
5123  FIRLexer lexer(sourceMgr, context);
5124  FIRVersion version = defaultFIRVersion;
5125  if (FIRCircuitParser(state, lexer, *module, version)
5126  .parseCircuit(annotationsBufs, omirBufs, ts))
5127  return nullptr;
5128 
5129  // Make sure the parse module has no other structural problems detected by
5130  // the verifier.
5131  auto circuitVerificationTimer = ts.nest("Verify circuit");
5132  if (failed(verify(*module)))
5133  return {};
5134 
5135  return module;
5136 }
5137 
5139  static mlir::TranslateToMLIRRegistration fromFIR(
5140  "import-firrtl", "import .fir",
5141  [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
5142  mlir::TimingScope ts;
5143  return importFIRFile(sourceMgr, context, ts);
5144  });
5145 }
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
Definition: CHIRRTL.cpp:26
MlirType elementType
Definition: CHIRRTL.cpp:25
static ParseResult parseParameterList(OpAsmParser &parser, SmallVector< Attribute > &parameters)
Parse an parameter list if present.
Definition: CalyxOps.cpp:1841
std::vector< UnbundledValueEntry > UnbundledValuesList
Definition: FIRParser.cpp:1143
SmallVector< std::pair< Attribute, Value > > UnbundledValueEntry
Definition: FIRParser.cpp:1142
llvm::StringMap< std::pair< SMLoc, SymbolValueEntry >, llvm::BumpPtrAllocator > ModuleSymbolTable
Definition: FIRParser.cpp:1139
llvm::PointerUnion< Value, UnbundledID > SymbolValueEntry
Definition: FIRParser.cpp:1136
llvm::DenseMap< std::pair< Value, unsigned >, Value > SubaccessCache
Definition: FIRParser.cpp:1157
ModuleSymbolTable::MapEntryTy ModuleSymbolTableEntry
Definition: FIRParser.cpp:1140
llvm::PointerEmbeddedInt< unsigned, 31 > UnbundledID
Definition: FIRParser.cpp:1135
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
int32_t width
Definition: FIRRTL.cpp:27
static ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
Builder builder
static int64_t size(hw::ArrayType mType, capnp::schema::Field::Reader cField)
Returns the expected size of an array (capnp list) in 64-bit words.
Definition: Schema.cpp:193
This helper class is used to handle Info records, which specify higher level symbolic source location...
Definition: FIRParser.cpp:338
std::optional< Location > infoLoc
This is the location specified by the @ marker if present.
Definition: FIRParser.cpp:391
LocWithInfo(SMLoc firLoc, FIRParser *parser)
Definition: FIRParser.cpp:340
void setDefaultLoc(Location loc)
If we didn't parse an info locator for the specified value, this sets a default, overriding a fall ba...
Definition: FIRParser.cpp:378
FIRParser *const parser
Definition: FIRParser.cpp:384
SMLoc firLoc
This is the designated location in the .fir file for use when there is no @ info marker.
Definition: FIRParser.cpp:388
ParseResult parseOptionalInfo()
Parse an @info marker if present and update our location.
Definition: FIRParser.cpp:354
SMLoc getFIRLoc() const
Definition: FIRParser.cpp:343
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
This is the common base class between SIntType and UIntType.
Definition: FIRRTLTypes.h:291
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.
int main(int argc, const char *argv[])
Definition: esiquery.cpp:25
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:53
mlir::Type innerType(mlir::Type type)
Definition: ESITypes.cpp:177
Forceable replaceWithNewForceability(Forceable op, bool forceable, ::mlir::PatternRewriter *rewriter=nullptr)
Replace a Forceable op with equivalent, changing whether forceable.
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
constexpr FIRVersion defaultFIRVersion(1, 0, 0)
Flow swapFlow(Flow flow)
Get a flow's reverse.
Definition: FIRRTLOps.cpp:154
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
void registerFromFIRFileTranslation()
Definition: FIRParser.cpp:5138
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.
Definition: FIRRTLOps.cpp:180
constexpr const char * rawAnnotations
mlir::OwningOpRef< mlir::ModuleOp > importFIRFile(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, FIRParserOptions options={})
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.
bool areTypesWeaklyEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destFlip=false, bool srcFlip=false, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false)
Returns true if two types are weakly 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.
ParseResult foldWhenEncodedVerifOp(PrintFOp printOp)
Chisel has a tendency to emit complex assert/assume/cover statements encoded as print operations with...
Value getValueByFieldID(ImplicitLocOpBuilder builder, Value value, unsigned fieldID)
This gets the value targeted by a field id.
bool fromJSONRaw(llvm::json::Value &value, SmallVectorImpl< Attribute > &annotations, llvm::json::Path path, MLIRContext *context)
constexpr FIRVersion minimumFIRVersion(0, 2, 0)
bool fromOMIRJSON(llvm::json::Value &value, SmallVectorImpl< Attribute > &annotations, llvm::json::Path path, MLIRContext *context)
Convert a JSON value containing OMIR JSON (an array of OMNodes), convert this to an OMIRAnnotation,...
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
Definition: FIRRTLUtils.cpp:23
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
unsigned numAnnotationFiles
The number of annotation files that were specified on the command line.
Definition: FIRParser.h:48
InfoLocHandling
Specify how @info locators should be handled.
Definition: FIRParser.h:33
@ IgnoreInfo
If this is set to true, the @info locators are ignored, and the locations are set to the location in ...
The FIRRTL specification version.
Definition: FIRParser.h:80
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.
StringRef getName() const