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