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