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