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