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