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