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