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 parseStringConcatExp(Value &result);
2012 ParseResult parseUnsafeDomainCast(Value &result);
2013 ParseResult parseUnknownProperty(Value &result);
2014
2015 template <typename T, size_t M, size_t N, size_t... Ms, size_t... Ns>
2016 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
2017 Value &result) {
2018 auto loc = getToken().getLoc();
2019 locationProcessor.setLoc(loc);
2020 consumeToken();
2021
2022 auto vals = std::array<Value, M>();
2023 auto ints = std::array<int64_t, N>();
2024
2025 // Parse all the values.
2026 bool first = true;
2027 for (size_t i = 0; i < M; ++i) {
2028 if (!first)
2029 if (parseToken(FIRToken::comma, "expected ','"))
2030 return failure();
2031 if (parseExp(vals[i], "expected expression in primitive operand"))
2032 return failure();
2033 first = false;
2034 }
2035
2036 // Parse all the attributes.
2037 for (size_t i = 0; i < N; ++i) {
2038 if (!first)
2039 if (parseToken(FIRToken::comma, "expected ','"))
2040 return failure();
2041 if (parseIntLit(ints[i], "expected integer in primitive operand"))
2042 return failure();
2043 first = false;
2044 }
2045
2046 if (parseToken(FIRToken::r_paren, "expected ')'"))
2047 return failure();
2048
2049 // Infer the type.
2050 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
2051 ints[Ns]..., {});
2052 if (!type) {
2053 // Only call translateLocation on an error case, it is expensive.
2054 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
2055 translateLocation(loc));
2056 return failure();
2057 }
2058
2059 // Create the operation.
2060 auto op = T::create(builder, type, vals[Ms]..., ints[Ns]...);
2061 result = op.getResult();
2062 return success();
2063 }
2064
2065 template <typename T, unsigned M, unsigned N>
2066 ParseResult parsePrimExp(Value &result) {
2067 auto ms = std::make_index_sequence<M>();
2068 auto ns = std::make_index_sequence<N>();
2069 return parsePrim<T, M, N>(ms, ns, result);
2070 }
2071
2072 std::optional<ParseResult> parseExpWithLeadingKeyword(FIRToken keyword);
2073
2074 // Stmt Parsing
2075 ParseResult parseSubBlock(Block &blockToInsertInto, unsigned indent,
2076 SymbolRefAttr layerSym);
2077 ParseResult parseAttach();
2078 ParseResult parseMemPort(MemDirAttr direction);
2079
2080 // Parse a format string and build operations for FIRRTL "special"
2081 // substitutions. Set `formatStringResult` to the validated format string and
2082 // `operands` to the list of actual operands.
2083 ParseResult parseFormatString(SMLoc formatStringLoc, StringRef formatString,
2084 ArrayRef<Value> specOperands,
2085 StringAttr &formatStringResult,
2086 SmallVectorImpl<Value> &operands);
2087 ParseResult parsePrintf();
2088 ParseResult parseFPrintf();
2089 ParseResult parseFFlush();
2090 ParseResult parseSkip();
2091 ParseResult parseStop();
2092 ParseResult parseAssert();
2093 ParseResult parseAssume();
2094 ParseResult parseCover();
2095 ParseResult parseWhen(unsigned whenIndent);
2096 ParseResult parseMatch(unsigned matchIndent);
2097 ParseResult parseDomainInstantiation();
2098 ParseResult parseDomainDefine();
2099 ParseResult parseRefDefine();
2100 ParseResult parseRefForce();
2101 ParseResult parseRefForceInitial();
2102 ParseResult parseRefRelease();
2103 ParseResult parseRefReleaseInitial();
2104 ParseResult parseRefRead(Value &result);
2105 ParseResult parseProbe(Value &result);
2106 ParseResult parsePropAssign();
2107 ParseResult parseRWProbe(Value &result);
2108 ParseResult parseLeadingExpStmt(Value lhs);
2109 ParseResult parseConnect();
2110 ParseResult parseInvalidate();
2111 ParseResult parseLayerBlockOrGroup(unsigned indent);
2112
2113 // Declarations
2114 ParseResult parseInstance();
2115 ParseResult parseInstanceChoice();
2116 ParseResult parseObject();
2117 ParseResult parseCombMem();
2118 ParseResult parseSeqMem();
2119 ParseResult parseMem(unsigned memIndent);
2120 ParseResult parseNode();
2121 ParseResult parseWire();
2122 ParseResult parseRegister(unsigned regIndent);
2123 ParseResult parseRegisterWithReset();
2124 ParseResult parseContract(unsigned blockIndent);
2125
2126 // Helper to fetch a module referenced by an instance-like statement.
2127 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
2128
2129 // The builder to build into.
2130 ImplicitLocOpBuilder builder;
2131 LazyLocationListener locationProcessor;
2132
2133 // Extra information maintained across a module.
2134 FIRModuleContext &moduleContext;
2135
2136 /// Inner symbol users to fixup after parsing.
2137 InnerSymFixups &innerSymFixups;
2138
2139 // An optional symbol that contains the current layer block that we are in.
2140 // This is used to construct a nested symbol for a layer block operation.
2141 SymbolRefAttr layerSym;
2142
2143 const SymbolTable &circuitSymTbl;
2144};
2145
2146} // end anonymous namespace
2147
2148/// Attach invalid values to every element of the value.
2149// NOLINTNEXTLINE(misc-no-recursion)
2150void FIRStmtParser::emitInvalidate(Value val, Flow flow) {
2151 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
2152 // Invalidate does nothing for non-base types.
2153 // When aggregates-of-refs are supported, instead check 'containsReference'
2154 // below.
2155 if (!tpe)
2156 return;
2157
2158 auto props = tpe.getRecursiveTypeProperties();
2159 if (props.isPassive && !props.containsAnalog) {
2160 if (flow == Flow::Source)
2161 return;
2162 emitConnect(builder, val, InvalidValueOp::create(builder, tpe));
2163 return;
2164 }
2165
2166 // Recurse until we hit passive leaves. Connect any leaves which have sink or
2167 // duplex flow.
2168 //
2169 // TODO: This is very similar to connect expansion in the LowerTypes pass
2170 // works. Find a way to unify this with methods common to LowerTypes or to
2171 // have LowerTypes to the actual work here, e.g., emitting a partial connect
2172 // to only the leaf sources.
2173 TypeSwitch<FIRRTLType>(tpe)
2174 .Case<BundleType>([&](auto tpe) {
2175 for (size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
2176 auto &subfield = moduleContext.getCachedSubaccess(val, i);
2177 if (!subfield) {
2178 OpBuilder::InsertionGuard guard(builder);
2179 builder.setInsertionPointAfterValue(val);
2180 subfield = SubfieldOp::create(builder, val, i);
2181 }
2182 emitInvalidate(subfield,
2183 tpe.getElement(i).isFlip ? swapFlow(flow) : flow);
2184 }
2185 })
2186 .Case<FVectorType>([&](auto tpe) {
2187 auto tpex = tpe.getElementType();
2188 for (size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2189 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2190 if (!subindex) {
2191 OpBuilder::InsertionGuard guard(builder);
2192 builder.setInsertionPointAfterValue(val);
2193 subindex = SubindexOp::create(builder, tpex, val, i);
2194 }
2195 emitInvalidate(subindex, flow);
2196 }
2197 });
2198}
2199
2200//===-------------------------------
2201// FIRStmtParser Expression Parsing.
2202
2203/// Parse the 'exp' grammar, returning all of the suboperations in the
2204/// specified vector, and the ultimate SSA value in value.
2205///
2206/// exp ::= id // Ref
2207/// ::= prim
2208/// ::= integer-literal-exp
2209/// ::= enum-exp
2210/// ::= list-exp
2211/// ::= 'String(' stringLit ')'
2212/// ::= exp '.' fieldId
2213/// ::= exp '[' intLit ']'
2214/// XX ::= exp '.' DoubleLit // TODO Workaround for #470
2215/// ::= exp '[' exp ']'
2216///
2217///
2218/// If 'isLeadingStmt' is true, then this is being called to parse the first
2219/// expression in a statement. We can handle some weird cases due to this if
2220/// we end up parsing the whole statement. In that case we return success, but
2221/// set the 'result' value to null.
2222// NOLINTNEXTLINE(misc-no-recursion)
2223ParseResult FIRStmtParser::parseExpImpl(Value &result, const Twine &message,
2224 bool isLeadingStmt) {
2225 auto token = getToken();
2226 auto kind = token.getKind();
2227 switch (kind) {
2228 case FIRToken::lp_integer_add:
2229 case FIRToken::lp_integer_mul:
2230 case FIRToken::lp_integer_shr:
2231 case FIRToken::lp_integer_shl:
2232 if (requireFeature({4, 0, 0}, "Integer arithmetic expressions"))
2233 return failure();
2234 break;
2235 default:
2236 break;
2237 }
2238
2239 switch (kind) {
2240 // Handle all primitive's.
2241#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES, \
2242 VERSION, FEATURE) \
2243 case FIRToken::lp_##SPELLING: \
2244 if (requireFeature(VERSION, FEATURE)) \
2245 return failure(); \
2246 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2247 return failure(); \
2248 break;
2249#include "FIRTokenKinds.def"
2250
2251 case FIRToken::l_brace_bar:
2252 if (isLeadingStmt)
2253 return emitError("unexpected enumeration as start of statement");
2254 if (parseEnumExp(result))
2255 return failure();
2256 break;
2257 case FIRToken::lp_read:
2258 if (isLeadingStmt)
2259 return emitError("unexpected read() as start of statement");
2260 if (parseRefRead(result))
2261 return failure();
2262 break;
2263 case FIRToken::lp_probe:
2264 if (isLeadingStmt)
2265 return emitError("unexpected probe() as start of statement");
2266 if (parseProbe(result))
2267 return failure();
2268 break;
2269 case FIRToken::lp_rwprobe:
2270 if (isLeadingStmt)
2271 return emitError("unexpected rwprobe() as start of statement");
2272 if (parseRWProbe(result))
2273 return failure();
2274 break;
2275
2276 case FIRToken::langle_UInt:
2277 case FIRToken::langle_SInt: {
2278 // The '<' has already been consumed by the lexer, so we need to parse
2279 // the mandatory width and '>'.
2280 bool isSigned = getToken().is(FIRToken::langle_SInt);
2281 consumeToken();
2282 int32_t width;
2283 if (parseWidth(width))
2284 return failure();
2285
2286 // Now parse the '(' intLit ')' part.
2287 if (parseIntegerLiteralExp(result, isSigned, width))
2288 return failure();
2289 break;
2290 }
2291
2292 case FIRToken::lp_UInt:
2293 if (parseIntegerLiteralExp(result, /*isSigned=*/false))
2294 return failure();
2295 break;
2296 case FIRToken::lp_SInt:
2297 if (parseIntegerLiteralExp(result, /*isSigned=*/true))
2298 return failure();
2299 break;
2300 case FIRToken::lp_String: {
2301 if (requireFeature({3, 1, 0}, "Strings"))
2302 return failure();
2303 locationProcessor.setLoc(getToken().getLoc());
2304 consumeToken(FIRToken::lp_String);
2305 StringRef spelling;
2306 if (parseGetSpelling(spelling) ||
2307 parseToken(FIRToken::string,
2308 "expected string literal in String expression") ||
2309 parseToken(FIRToken::r_paren, "expected ')' in String expression"))
2310 return failure();
2311 auto attr = builder.getStringAttr(FIRToken::getStringValue(spelling));
2312 result = moduleContext.getCachedConstant<StringConstantOp>(
2313 builder, attr, builder.getType<StringType>(), attr);
2314 break;
2315 }
2316 case FIRToken::lp_Integer: {
2317 if (requireFeature({3, 1, 0}, "Integers"))
2318 return failure();
2319 locationProcessor.setLoc(getToken().getLoc());
2320 consumeToken(FIRToken::lp_Integer);
2321 APInt value;
2322 if (parseIntLit(value, "expected integer literal in Integer expression") ||
2323 parseToken(FIRToken::r_paren, "expected ')' in Integer expression"))
2324 return failure();
2325 APSInt apint(value, /*isUnsigned=*/false);
2326 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2327 builder, IntegerAttr::get(getContext(), apint),
2328 builder.getType<FIntegerType>(), apint);
2329 break;
2330 }
2331 case FIRToken::lp_Bool: {
2332 if (requireFeature(missingSpecFIRVersion, "Bools"))
2333 return failure();
2334 locationProcessor.setLoc(getToken().getLoc());
2335 consumeToken(FIRToken::lp_Bool);
2336 bool value;
2337 if (consumeIf(FIRToken::kw_true))
2338 value = true;
2339 else if (consumeIf(FIRToken::kw_false))
2340 value = false;
2341 else
2342 return emitError("expected true or false in Bool expression");
2343 if (parseToken(FIRToken::r_paren, "expected ')' in Bool expression"))
2344 return failure();
2345 auto attr = builder.getBoolAttr(value);
2346 result = moduleContext.getCachedConstant<BoolConstantOp>(
2347 builder, attr, builder.getType<BoolType>(), value);
2348 break;
2349 }
2350 case FIRToken::lp_Double: {
2351 if (requireFeature(missingSpecFIRVersion, "Doubles"))
2352 return failure();
2353 locationProcessor.setLoc(getToken().getLoc());
2354 consumeToken(FIRToken::lp_Double);
2355 auto spelling = getTokenSpelling();
2356 if (parseToken(FIRToken::floatingpoint,
2357 "expected floating point in Double expression") ||
2358 parseToken(FIRToken::r_paren, "expected ')' in Double expression"))
2359 return failure();
2360 // NaN, INF, exponent, hex, integer?
2361 // This uses `strtod` internally, FWIW. See `man 3 strtod`.
2362 double d;
2363 if (!llvm::to_float(spelling, d))
2364 return emitError("invalid double");
2365 auto attr = builder.getF64FloatAttr(d);
2366 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2367 builder, attr, builder.getType<DoubleType>(), attr);
2368 break;
2369 }
2370 case FIRToken::lp_List:
2371 case FIRToken::langle_List: {
2372 if (requireFeature({4, 0, 0}, "Lists"))
2373 return failure();
2374 if (isLeadingStmt)
2375 return emitError("unexpected List<>() as start of statement");
2376 if (parseListExp(result))
2377 return failure();
2378 break;
2379 }
2380
2381 case FIRToken::lp_list_concat: {
2382 if (isLeadingStmt)
2383 return emitError("unexpected list_create() as start of statement");
2384 if (requireFeature({4, 0, 0}, "List concat") || parseListConcatExp(result))
2385 return failure();
2386 break;
2387 }
2388
2389 case FIRToken::lp_path:
2390 if (isLeadingStmt)
2391 return emitError("unexpected path() as start of statement");
2392 if (requireFeature(missingSpecFIRVersion, "Paths") || parsePathExp(result))
2393 return failure();
2394 break;
2395
2396 case FIRToken::lp_intrinsic:
2397 if (requireFeature({4, 0, 0}, "generic intrinsics") ||
2398 parseIntrinsicExp(result))
2399 return failure();
2400 break;
2401
2402 case FIRToken::lp_cat:
2403 if (parseCatExp(result))
2404 return failure();
2405 break;
2406
2407 case FIRToken::lp_string_concat:
2408 if (parseStringConcatExp(result))
2409 return failure();
2410 break;
2411
2412 case FIRToken::lp_unsafe_domain_cast:
2413 if (requireFeature(nextFIRVersion, "unsafe_domain_cast") ||
2414 parseUnsafeDomainCast(result))
2415 return failure();
2416 break;
2417 case FIRToken::lp_Unknown:
2418 if (requireFeature(nextFIRVersion, "unknown property expressions") ||
2419 parseUnknownProperty(result))
2420 return failure();
2421 break;
2422
2423 // Otherwise there are a bunch of keywords that are treated as identifiers
2424 // try them.
2425 case FIRToken::identifier: // exp ::= id
2426 case FIRToken::literal_identifier:
2427 case FIRToken::kw_UInt:
2428 case FIRToken::kw_SInt:
2429 case FIRToken::kw_String:
2430 case FIRToken::kw_Integer:
2431 case FIRToken::kw_Bool:
2432 case FIRToken::kw_Double:
2433 case FIRToken::kw_List:
2434 default: {
2435 StringRef name;
2436 auto loc = getToken().getLoc();
2437 SymbolValueEntry symtabEntry;
2438 if (parseId(name, message) ||
2439 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2440 return failure();
2441
2442 // If we looked up a normal value, then we're done.
2443 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc, false))
2444 break;
2445
2446 assert(isa<UnbundledID>(symtabEntry) && "should be an instance");
2447
2448 // Otherwise we referred to an implicitly bundled value. We *must* be in
2449 // the midst of processing a field ID reference or 'is invalid'. If not,
2450 // this is an error.
2451 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2452 if (parseToken(FIRToken::kw_invalid, "expected 'invalid'") ||
2453 parseOptionalInfo())
2454 return failure();
2455
2456 locationProcessor.setLoc(loc);
2457 // Invalidate all of the results of the bundled value.
2458 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2459 UnbundledValueEntry &ubEntry =
2460 moduleContext.getUnbundledEntry(unbundledId);
2461 for (auto elt : ubEntry)
2462 emitInvalidate(elt.second);
2463
2464 // Signify that we parsed the whole statement.
2465 result = Value();
2466 return success();
2467 }
2468
2469 // Handle the normal "instance.x" reference.
2470 StringRef fieldName;
2471 if (parseToken(FIRToken::period, "expected '.' in field reference") ||
2472 parseFieldId(fieldName, "expected field name") ||
2473 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2474 return failure();
2475 break;
2476 }
2477 }
2478 // Don't add code here, the common cases of these switch statements will be
2479 // merged. This allows for fixing up primops after they have been created.
2480 switch (kind) {
2481 case FIRToken::lp_shr:
2482 // For FIRRTL versions earlier than 4.0.0, insert pad(_, 1) around any
2483 // unsigned shr This ensures the minimum width is 1 (but can be greater)
2484 if (version < FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2485 result = PadPrimOp::create(builder, result, 1);
2486 break;
2487 default:
2488 break;
2489 }
2490
2491 return parseOptionalExpPostscript(result);
2492}
2493
2494/// Parse the postfix productions of expression after the leading expression
2495/// has been parsed.
2496///
2497/// exp ::= exp '.' fieldId
2498/// ::= exp '[' intLit ']'
2499/// XX ::= exp '.' DoubleLit // TODO Workaround for #470
2500/// ::= exp '[' exp ']'
2501ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2502 bool allowDynamic) {
2503
2504 // Handle postfix expressions.
2505 while (true) {
2506 // Subfield: exp ::= exp '.' fieldId
2507 if (consumeIf(FIRToken::period)) {
2508 if (parsePostFixFieldId(result))
2509 return failure();
2510
2511 continue;
2512 }
2513
2514 // Subindex: exp ::= exp '[' intLit ']' | exp '[' exp ']'
2515 if (consumeIf(FIRToken::l_square)) {
2516 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2517 if (parsePostFixIntSubscript(result))
2518 return failure();
2519 continue;
2520 }
2521 if (!allowDynamic)
2522 return emitError("subaccess not allowed here");
2523 if (parsePostFixDynamicSubscript(result))
2524 return failure();
2525
2526 continue;
2527 }
2528
2529 return success();
2530 }
2531}
2532
2533template <typename subop>
2534FailureOr<Value>
2535FIRStmtParser::emitCachedSubAccess(Value base, unsigned indexNo, SMLoc loc) {
2536 // Check if we already have created this Subindex op.
2537 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2538 if (value)
2539 return value;
2540
2541 // Make sure the field name matches up with the input value's type and
2542 // compute the result type for the expression.
2543 auto baseType = cast<FIRRTLType>(base.getType());
2544 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2545 if (!resultType) {
2546 // Emit the error at the right location. translateLocation is expensive.
2547 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2548 return failure();
2549 }
2550
2551 // Create the result operation, inserting at the location of the declaration.
2552 // This will cache the subfield operation for further uses.
2553 locationProcessor.setLoc(loc);
2554 OpBuilder::InsertionGuard guard(builder);
2555 builder.setInsertionPointAfterValue(base);
2556 auto op = subop::create(builder, resultType, base, indexNo);
2557
2558 // Insert the newly created operation into the cache.
2559 return value = op.getResult();
2560}
2561
2562/// exp ::= exp '.' fieldId
2563///
2564/// The "exp '.'" part of the production has already been parsed.
2565///
2566ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2567 auto loc = getToken().getLoc();
2568 SmallVector<StringRef, 3> fields;
2569 if (parseFieldIdSeq(fields, "expected field name"))
2570 return failure();
2571 for (auto fieldName : fields) {
2572 std::optional<unsigned> indexV;
2573 auto type = result.getType();
2574 if (auto refTy = type_dyn_cast<RefType>(type))
2575 type = refTy.getType();
2576 if (auto bundle = type_dyn_cast<BundleType>(type))
2577 indexV = bundle.getElementIndex(fieldName);
2578 else if (auto bundle = type_dyn_cast<OpenBundleType>(type))
2579 indexV = bundle.getElementIndex(fieldName);
2580 else if (auto klass = type_dyn_cast<ClassType>(type))
2581 indexV = klass.getElementIndex(fieldName);
2582 else if (auto domain = type_dyn_cast<DomainType>(type))
2583 indexV = domain.getFieldIndex(fieldName);
2584 else
2585 return emitError(loc,
2586 "subfield requires bundle, object, or domain operand ");
2587 if (!indexV)
2588 return emitError(loc, "unknown field '" + fieldName + "' in type ")
2589 << result.getType();
2590 auto indexNo = *indexV;
2591
2592 FailureOr<Value> subResult;
2593 if (type_isa<RefType>(result.getType()))
2594 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2595 else if (type_isa<ClassType>(type))
2596 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2597 else if (type_isa<DomainType>(type))
2598 subResult = emitCachedSubAccess<DomainSubfieldOp>(result, indexNo, loc);
2599 else if (type_isa<BundleType>(type))
2600 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2601 else
2602 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2603
2604 if (failed(subResult))
2605 return failure();
2606 result = *subResult;
2607 }
2608 return success();
2609}
2610
2611/// exp ::= exp '[' intLit ']'
2612///
2613/// The "exp '['" part of the production has already been parsed.
2614///
2615ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2616 auto loc = getToken().getLoc();
2617 int32_t indexNo;
2618 if (parseIntLit(indexNo, "expected index") ||
2619 parseToken(FIRToken::r_square, "expected ']'"))
2620 return failure();
2621
2622 if (indexNo < 0)
2623 return emitError(loc, "invalid index specifier"), failure();
2624
2625 FailureOr<Value> subResult;
2626 if (type_isa<RefType>(result.getType()))
2627 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2628 else if (type_isa<FVectorType>(result.getType()))
2629 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2630 else
2631 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2632
2633 if (failed(subResult))
2634 return failure();
2635 result = *subResult;
2636 return success();
2637}
2638
2639/// exp ::= exp '[' exp ']'
2640///
2641/// The "exp '['" part of the production has already been parsed.
2642///
2643ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2644 auto loc = getToken().getLoc();
2645 Value index;
2646 if (parseExp(index, "expected subscript index expression") ||
2647 parseToken(FIRToken::r_square, "expected ']' in subscript"))
2648 return failure();
2649
2650 // If the index expression is a flip type, strip it off.
2651 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2652 if (!indexType)
2653 return emitError("expected base type for index expression");
2654 indexType = indexType.getPassiveType();
2655 locationProcessor.setLoc(loc);
2656
2657 // Make sure the index expression is valid and compute the result type for the
2658 // expression.
2659 auto resultType =
2660 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2661 if (!resultType) {
2662 // Emit the error at the right location. translateLocation is expensive.
2663 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2664 translateLocation(loc));
2665 return failure();
2666 }
2667
2668 // Create the result operation.
2669 auto op = SubaccessOp::create(builder, resultType, result, index);
2670 result = op.getResult();
2671 return success();
2672}
2673
2674/// integer-literal-exp ::= 'UInt' optional-width '(' intLit ')'
2675/// ::= 'SInt' optional-width '(' intLit ')'
2676///
2677/// If allocatedWidth is provided, it means the width was already parsed
2678/// (e.g., from a langle_UInt token) and should be used instead of parsing
2679/// it from the token stream.
2680ParseResult
2681FIRStmtParser::parseIntegerLiteralExp(Value &result, bool isSigned,
2682 std::optional<int32_t> allocatedWidth) {
2683 auto loc = getToken().getLoc();
2684
2685 // Determine if '(' was already consumed by the lexer.
2686 bool hasLParen = getToken().isAny(FIRToken::lp_UInt, FIRToken::lp_SInt);
2687 if (hasLParen)
2688 consumeToken();
2689
2690 // Parse a width specifier if not already provided.
2691 int32_t width = allocatedWidth.value_or(-1);
2692 APInt value;
2693
2694 // If we consumed an lp_ token, the '(' was already consumed by the lexer.
2695 // Otherwise, we need to parse it.
2696 if (!hasLParen &&
2697 parseToken(FIRToken::l_paren, "expected '(' in integer expression"))
2698 return failure();
2699
2700 if (parseIntLit(value, "expected integer value") ||
2701 parseToken(FIRToken::r_paren, "expected ')' in integer expression"))
2702 return failure();
2703
2704 // Construct an integer attribute of the right width.
2705 // Literals are parsed as 'const' types.
2706 auto type = IntType::get(builder.getContext(), isSigned, width, true);
2707
2708 IntegerType::SignednessSemantics signedness =
2709 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2710 if (width == 0) {
2711 if (!value.isZero())
2712 return emitError(loc, "zero bit constant must be zero");
2713 value = value.trunc(0);
2714 } else if (width != -1) {
2715 // Convert to the type's width, checking value fits in destination width.
2716 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2717 if (!valueFits)
2718 return emitError(loc, "initializer too wide for declared width");
2719 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2720 }
2721
2722 Type attrType =
2723 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2724 auto attr = builder.getIntegerAttr(attrType, value);
2725
2726 locationProcessor.setLoc(loc);
2727 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2728 return success();
2729}
2730
2731/// list-exp ::= list-type '(' exp* ')'
2732ParseResult FIRStmtParser::parseListExp(Value &result) {
2733 auto loc = getToken().getLoc();
2734 bool hasLAngle = getToken().is(FIRToken::langle_List);
2735 bool hasLParen = getToken().is(FIRToken::lp_List);
2736 consumeToken();
2737
2739 // If we consumed a langle_ token, the '<' was already consumed by the lexer.
2740 if (!hasLAngle && parseToken(FIRToken::less, "expected '<' in List type"))
2741 return failure();
2742
2743 if (parsePropertyType(elementType, "expected List element type") ||
2744 parseToken(FIRToken::greater, "expected '>' in List type"))
2745 return failure();
2746
2747 auto listType = ListType::get(getContext(), elementType);
2748
2749 // If we consumed an lp_ token, the '(' was already consumed by the lexer.
2750 if (!hasLParen &&
2751 parseToken(FIRToken::l_paren, "expected '(' in List expression"))
2752 return failure();
2753
2754 SmallVector<Value, 3> operands;
2755 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2756 Value operand;
2757 locationProcessor.setLoc(loc);
2758 if (parseExp(operand, "expected expression in List expression"))
2759 return failure();
2760
2761 if (operand.getType() != elementType) {
2762 if (!isa<AnyRefType>(elementType) ||
2763 !isa<ClassType>(operand.getType()))
2764 return emitError(loc, "unexpected expression of type ")
2765 << operand.getType() << " in List expression of type "
2766 << elementType;
2767 operand = ObjectAnyRefCastOp::create(builder, operand);
2768 }
2769
2770 operands.push_back(operand);
2771 return success();
2772 }))
2773 return failure();
2774
2775 locationProcessor.setLoc(loc);
2776 result = ListCreateOp::create(builder, listType, operands);
2777 return success();
2778}
2779
2780/// list-concat-exp ::= 'list_concat' '(' exp* ')'
2781ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2782 consumeToken(FIRToken::lp_list_concat);
2783
2784 auto loc = getToken().getLoc();
2785 ListType type;
2786 SmallVector<Value, 3> operands;
2787 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2788 Value operand;
2789 locationProcessor.setLoc(loc);
2790 if (parseExp(operand, "expected expression in List concat expression"))
2791 return failure();
2792
2793 if (!type_isa<ListType>(operand.getType()))
2794 return emitError(loc, "unexpected expression of type ")
2795 << operand.getType() << " in List concat expression";
2796
2797 if (!type)
2798 type = type_cast<ListType>(operand.getType());
2799
2800 if (operand.getType() != type)
2801 return emitError(loc, "unexpected expression of type ")
2802 << operand.getType() << " in List concat expression of type "
2803 << type;
2804
2805 operands.push_back(operand);
2806 return success();
2807 }))
2808 return failure();
2809
2810 if (operands.empty())
2811 return emitError(loc, "need at least one List to concatenate");
2812
2813 locationProcessor.setLoc(loc);
2814 result = ListConcatOp::create(builder, type, operands);
2815 return success();
2816}
2817
2818/// cat-exp ::= 'cat(' exp* ')'
2819ParseResult FIRStmtParser::parseCatExp(Value &result) {
2820 consumeToken(FIRToken::lp_cat);
2821
2822 auto loc = getToken().getLoc();
2823 SmallVector<Value, 3> operands;
2824 std::optional<bool> isSigned;
2825 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2826 Value operand;
2827 locationProcessor.setLoc(loc);
2828 auto operandLoc = getToken().getLoc();
2829 if (parseExp(operand, "expected expression in cat expression"))
2830 return failure();
2831 if (!type_isa<IntType>(operand.getType())) {
2832 auto diag = emitError(loc, "all operands must be Int type");
2833 diag.attachNote(translateLocation(operandLoc))
2834 << "non-integer operand is here";
2835 return failure();
2836 }
2837 if (!isSigned)
2838 isSigned = type_isa<SIntType>(operand.getType());
2839 else if (type_isa<SIntType>(operand.getType()) != *isSigned) {
2840 auto diag = emitError(loc, "all operands must have same signedness");
2841 diag.attachNote(translateLocation(operandLoc))
2842 << "operand with different signedness is here";
2843 return failure();
2844 }
2845
2846 operands.push_back(operand);
2847 return success();
2848 }))
2849 return failure();
2850
2851 if (operands.size() != 2) {
2852 if (requireFeature(nextFIRVersion, "variadic cat", loc))
2853 return failure();
2854 }
2855
2856 locationProcessor.setLoc(loc);
2857 result = CatPrimOp::create(builder, operands);
2858 return success();
2859}
2860
2861/// string_concat-exp ::= 'string_concat(' exp* ')'
2862ParseResult FIRStmtParser::parseStringConcatExp(Value &result) {
2863 consumeToken(FIRToken::lp_string_concat);
2864
2865 auto loc = getToken().getLoc();
2866 SmallVector<Value, 3> operands;
2867 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2868 Value operand;
2869 locationProcessor.setLoc(loc);
2870 if (parseExp(operand,
2871 "expected expression in string_concat expression"))
2872 return failure();
2873 if (!type_isa<StringType>(operand.getType()))
2874 return emitError(loc, "all operands must be String type");
2875 operands.push_back(operand);
2876 return success();
2877 }))
2878 return failure();
2879
2880 if (operands.empty())
2881 return emitError(loc, "need at least one String to concatenate");
2882
2883 locationProcessor.setLoc(loc);
2884 auto type = StringType::get(builder.getContext());
2885 result = builder.create<StringConcatOp>(type, operands);
2886 return success();
2887}
2888
2889ParseResult FIRStmtParser::parseUnsafeDomainCast(Value &result) {
2890 consumeToken(FIRToken::lp_unsafe_domain_cast);
2891
2892 auto loc = getToken().getLoc();
2893 Value input;
2894 if (parseExp(input, "expected input"))
2895 return failure();
2896
2897 SmallVector<Value> domains;
2898 if (consumeIf(FIRToken::comma)) {
2899 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2900 Value domain;
2901 if (parseExp(domain, "expected domain"))
2902 return failure();
2903 domains.push_back(domain);
2904 return success();
2905 }))
2906 return failure();
2907 } else if (parseToken(FIRToken::r_paren, "expected closing parenthesis")) {
2908 return failure();
2909 }
2910
2911 locationProcessor.setLoc(loc);
2912 result = UnsafeDomainCastOp::create(builder, input, domains);
2913 return success();
2914}
2915
2916ParseResult FIRStmtParser::parseUnknownProperty(Value &result) {
2917 auto loc = getToken().getLoc();
2918 consumeToken(FIRToken::lp_Unknown);
2919 // The '(' has already been consumed by the lexer.
2920
2921 PropertyType type;
2922 if (parsePropertyType(type, "expected property type") ||
2923 parseToken(FIRToken::r_paren, "expected ')' in unknown property"))
2924 return failure();
2925
2926 locationProcessor.setLoc(loc);
2927 result = UnknownValueOp::create(builder, type);
2928 return success();
2929}
2930
2931/// The .fir grammar has the annoying property where:
2932/// 1) some statements start with keywords
2933/// 2) some start with an expression
2934/// 3) it allows the 'reference' expression to either be an identifier or a
2935/// keyword.
2936///
2937/// One example of this is something like, where this is not a register decl:
2938/// reg <- thing
2939///
2940/// Solving this requires lookahead to the second token. We handle it by
2941/// factoring the lookahead inline into the code to keep the parser fast.
2942///
2943/// As such, statements that start with a leading keyword call this method to
2944/// check to see if the keyword they consumed was actually the start of an
2945/// expression. If so, they parse the expression-based statement and return the
2946/// parser result. If not, they return None and the statement is parsed like
2947/// normal.
2948std::optional<ParseResult>
2949FIRStmtParser::parseExpWithLeadingKeyword(FIRToken keyword) {
2950 switch (getToken().getKind()) {
2951 default:
2952 // This isn't part of an expression, and isn't part of a statement.
2953 return std::nullopt;
2954
2955 case FIRToken::period: // exp `.` identifier
2956 case FIRToken::l_square: // exp `[` index `]`
2957 case FIRToken::kw_is: // exp is invalid
2958 case FIRToken::less_equal: // exp <= thing
2959 break;
2960 }
2961
2962 Value lhs;
2963 SymbolValueEntry symtabEntry;
2964 auto loc = keyword.getLoc();
2965
2966 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.getSpelling(), loc))
2967 return ParseResult(failure());
2968
2969 // If we have a '.', we might have a symbol or an expanded port. If we
2970 // resolve to a symbol, use that, otherwise check for expanded bundles of
2971 // other ops.
2972 // Non '.' ops take the plain symbol path.
2973 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc, false)) {
2974 // Ok if the base name didn't resolve by itself, it might be part of an
2975 // expanded dot reference. That doesn't work then we fail.
2976 if (!consumeIf(FIRToken::period))
2977 return ParseResult(failure());
2978
2979 StringRef fieldName;
2980 if (parseFieldId(fieldName, "expected field name") ||
2981 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2982 return ParseResult(failure());
2983 }
2984
2985 // Parse any further trailing things like "mem.x.y".
2986 if (parseOptionalExpPostscript(lhs))
2987 return ParseResult(failure());
2988
2989 return parseLeadingExpStmt(lhs);
2990}
2991//===-----------------------------
2992// FIRStmtParser Statement Parsing
2993
2994/// simple_stmt_block ::= simple_stmt*
2995ParseResult FIRStmtParser::parseSimpleStmtBlock(unsigned indent) {
2996 while (true) {
2997 // The outer level parser can handle these tokens.
2998 if (getToken().isAny(FIRToken::eof, FIRToken::error))
2999 return success();
3000
3001 auto subIndent = getIndentation();
3002 if (!subIndent.has_value())
3003 return emitError("expected statement to be on its own line"), failure();
3004
3005 if (*subIndent <= indent)
3006 return success();
3007
3008 // Let the statement parser handle this.
3009 if (parseSimpleStmt(*subIndent))
3010 return failure();
3011 }
3012}
3013
3014ParseResult FIRStmtParser::parseSimpleStmt(unsigned stmtIndent) {
3015 locationProcessor.startStatement();
3016 auto result = parseSimpleStmtImpl(stmtIndent);
3017 locationProcessor.endStatement(*this);
3018 return result;
3019}
3020
3021/// simple_stmt ::= stmt
3022///
3023/// stmt ::= attach
3024/// ::= memport
3025/// ::= printf
3026/// ::= skip
3027/// ::= stop
3028/// ::= when
3029/// ::= leading-exp-stmt
3030/// ::= define
3031/// ::= propassign
3032///
3033/// stmt ::= instance
3034/// ::= cmem | smem | mem
3035/// ::= node | wire
3036/// ::= register
3037/// ::= contract
3038///
3039ParseResult FIRStmtParser::parseSimpleStmtImpl(unsigned stmtIndent) {
3040 auto kind = getToken().getKind();
3041 /// Massage the kind based on the FIRRTL Version.
3042 switch (kind) {
3043 case FIRToken::kw_invalidate:
3044 case FIRToken::kw_connect:
3045 case FIRToken::kw_regreset:
3046 /// The "invalidate", "connect", and "regreset" keywords were added
3047 /// in 3.0.0.
3048 if (version < FIRVersion(3, 0, 0))
3049 kind = FIRToken::identifier;
3050 break;
3051 default:
3052 break;
3053 };
3054 switch (kind) {
3055 // Statements.
3056 case FIRToken::kw_attach:
3057 return parseAttach();
3058 case FIRToken::kw_infer:
3059 return parseMemPort(MemDirAttr::Infer);
3060 case FIRToken::kw_read:
3061 return parseMemPort(MemDirAttr::Read);
3062 case FIRToken::kw_write:
3063 return parseMemPort(MemDirAttr::Write);
3064 case FIRToken::kw_rdwr:
3065 return parseMemPort(MemDirAttr::ReadWrite);
3066 case FIRToken::kw_connect:
3067 return parseConnect();
3068 case FIRToken::kw_propassign:
3069 if (requireFeature({3, 1, 0}, "properties"))
3070 return failure();
3071 return parsePropAssign();
3072 case FIRToken::kw_invalidate:
3073 return parseInvalidate();
3074 case FIRToken::lp_printf:
3075 return parsePrintf();
3076 case FIRToken::lp_fprintf:
3077 return parseFPrintf();
3078 case FIRToken::lp_fflush:
3079 return parseFFlush();
3080 case FIRToken::kw_skip:
3081 return parseSkip();
3082 case FIRToken::lp_stop:
3083 return parseStop();
3084 case FIRToken::lp_assert:
3085 return parseAssert();
3086 case FIRToken::lp_assume:
3087 return parseAssume();
3088 case FIRToken::lp_cover:
3089 return parseCover();
3090 case FIRToken::kw_when:
3091 return parseWhen(stmtIndent);
3092 case FIRToken::kw_match:
3093 return parseMatch(stmtIndent);
3094 case FIRToken::kw_domain:
3095 // In module context, 'domain' is only valid for domain instantiation
3096 return parseDomainInstantiation();
3097 case FIRToken::kw_domain_define:
3098 return parseDomainDefine();
3099 case FIRToken::kw_define:
3100 return parseRefDefine();
3101 case FIRToken::lp_force:
3102 return parseRefForce();
3103 case FIRToken::lp_force_initial:
3104 return parseRefForceInitial();
3105 case FIRToken::lp_release:
3106 return parseRefRelease();
3107 case FIRToken::lp_release_initial:
3108 return parseRefReleaseInitial();
3109 case FIRToken::kw_group:
3110 if (requireFeature({3, 2, 0}, "optional groups") ||
3111 removedFeature({3, 3, 0}, "optional groups"))
3112 return failure();
3113 return parseLayerBlockOrGroup(stmtIndent);
3114 case FIRToken::kw_layerblock:
3115 if (requireFeature({3, 3, 0}, "layers"))
3116 return failure();
3117 return parseLayerBlockOrGroup(stmtIndent);
3118 case FIRToken::lp_intrinsic:
3119 if (requireFeature({4, 0, 0}, "generic intrinsics"))
3120 return failure();
3121 return parseIntrinsicStmt();
3122 default: {
3123 // Statement productions that start with an expression.
3124 Value lhs;
3125 if (parseExpLeadingStmt(lhs, "unexpected token in module"))
3126 return failure();
3127 // We use parseExp in a special mode that can complete the entire stmt
3128 // at once in unusual cases. If this happened, then we are done.
3129 if (!lhs)
3130 return success();
3131
3132 return parseLeadingExpStmt(lhs);
3133 }
3134
3135 // Declarations
3136 case FIRToken::kw_inst:
3137 return parseInstance();
3138 case FIRToken::kw_instchoice:
3139 return parseInstanceChoice();
3140 case FIRToken::kw_object:
3141 return parseObject();
3142 case FIRToken::kw_cmem:
3143 return parseCombMem();
3144 case FIRToken::kw_smem:
3145 return parseSeqMem();
3146 case FIRToken::kw_mem:
3147 return parseMem(stmtIndent);
3148 case FIRToken::kw_node:
3149 return parseNode();
3150 case FIRToken::kw_wire:
3151 return parseWire();
3152 case FIRToken::kw_reg:
3153 return parseRegister(stmtIndent);
3154 case FIRToken::kw_regreset:
3155 return parseRegisterWithReset();
3156 case FIRToken::kw_contract:
3157 return parseContract(stmtIndent);
3158 }
3159}
3160
3161ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
3162 unsigned indent,
3163 SymbolRefAttr layerSym) {
3164 // Declarations within the suite are scoped to within the suite.
3165 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
3166 moduleContext, &blockToInsertInto);
3167
3168 // After parsing the when region, we can release any new entries in
3169 // unbundledValues since the symbol table entries that refer to them will be
3170 // gone.
3171 UnbundledValueRestorer x(moduleContext.unbundledValues);
3172
3173 // We parse the substatements into their own parser, so they get inserted
3174 // into the specified 'when' region.
3175 auto subParser = std::make_unique<FIRStmtParser>(
3176 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
3177 layerSym);
3178
3179 // Figure out whether the body is a single statement or a nested one.
3180 auto stmtIndent = getIndentation();
3181
3182 // Parsing a single statment is straightforward.
3183 if (!stmtIndent.has_value())
3184 return subParser->parseSimpleStmt(indent);
3185
3186 if (*stmtIndent <= indent)
3187 return emitError("statement must be indented more than previous statement"),
3188 failure();
3189
3190 // Parse a block of statements that are indented more than the when.
3191 return subParser->parseSimpleStmtBlock(indent);
3192}
3193
3194/// attach ::= 'attach' '(' exp+ ')' info?
3195ParseResult FIRStmtParser::parseAttach() {
3196 auto startTok = consumeToken(FIRToken::kw_attach);
3197
3198 // If this was actually the start of a connect or something else handle that.
3199 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3200 return *isExpr;
3201
3202 if (parseToken(FIRToken::l_paren, "expected '(' after attach"))
3203 return failure();
3204
3205 SmallVector<Value, 4> operands;
3206 operands.push_back({});
3207 if (parseExp(operands.back(), "expected operand in attach"))
3208 return failure();
3209
3210 while (consumeIf(FIRToken::comma)) {
3211 operands.push_back({});
3212 if (parseExp(operands.back(), "expected operand in attach"))
3213 return failure();
3214 }
3215 if (parseToken(FIRToken::r_paren, "expected close paren"))
3216 return failure();
3217
3218 if (parseOptionalInfo())
3219 return failure();
3220
3221 locationProcessor.setLoc(startTok.getLoc());
3222 AttachOp::create(builder, operands);
3223 return success();
3224}
3225
3226/// stmt ::= mdir 'mport' id '=' id '[' exp ']' exp info?
3227/// mdir ::= 'infer' | 'read' | 'write' | 'rdwr'
3228///
3229ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
3230 auto startTok = consumeToken();
3231 auto startLoc = startTok.getLoc();
3232
3233 // If this was actually the start of a connect or something else handle
3234 // that.
3235 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3236 return *isExpr;
3237
3238 StringRef id;
3239 StringRef memName;
3240 SymbolValueEntry memorySym;
3241 Value memory, indexExp, clock;
3242 if (parseToken(FIRToken::kw_mport, "expected 'mport' in memory port") ||
3243 parseId(id, "expected result name") ||
3244 parseToken(FIRToken::equal, "expected '=' in memory port") ||
3245 parseId(memName, "expected memory name") ||
3246 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
3247 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
3248 parseToken(FIRToken::l_square, "expected '[' in memory port") ||
3249 parseExp(indexExp, "expected index expression") ||
3250 parseToken(FIRToken::r_square, "expected ']' in memory port") ||
3251 parseToken(FIRToken::comma, "expected ','") ||
3252 parseExp(clock, "expected clock expression") || parseOptionalInfo())
3253 return failure();
3254
3255 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
3256 if (!memVType)
3257 return emitError(startLoc,
3258 "memory port should have behavioral memory type");
3259 auto resultType = memVType.getElementType();
3260
3261 ArrayAttr annotations = getConstants().emptyArrayAttr;
3262 locationProcessor.setLoc(startLoc);
3263
3264 // Create the memory port at the location of the cmemory.
3265 Value memoryPort, memoryData;
3266 {
3267 OpBuilder::InsertionGuard guard(builder);
3268 builder.setInsertionPointAfterValue(memory);
3269 auto memoryPortOp = MemoryPortOp::create(
3270 builder, resultType, CMemoryPortType::get(getContext()), memory,
3271 direction, id, annotations);
3272 memoryData = memoryPortOp.getResult(0);
3273 memoryPort = memoryPortOp.getResult(1);
3274 }
3275
3276 // Create a memory port access in the current scope.
3277 MemoryPortAccessOp::create(builder, memoryPort, indexExp, clock);
3278
3279 return moduleContext.addSymbolEntry(id, memoryData, startLoc, true);
3280}
3281
3282// Parse a format string and build operations for FIRRTL "special"
3283// substitutions. Set `formatStringResult` to the validated format string and
3284// `operands` to the list of actual operands.
3285ParseResult FIRStmtParser::parseFormatString(SMLoc formatStringLoc,
3286 StringRef formatString,
3287 ArrayRef<Value> specOperands,
3288 StringAttr &formatStringResult,
3289 SmallVectorImpl<Value> &operands) {
3290 // For FIRRTL versions < 5.0.0, don't process special substitutions
3291 if (version < FIRVersion(5, 0, 0)) {
3292 operands.append(specOperands.begin(), specOperands.end());
3293 formatStringResult =
3294 builder.getStringAttr(FIRToken::getStringValue(formatString));
3295 return success();
3296 }
3297
3298 // Use the utility function to parse the format string
3299 auto loc = translateLocation(formatStringLoc);
3301 builder, loc, FIRToken::getStringValue(formatString), specOperands,
3302 formatStringResult, operands);
3303 return result;
3304}
3305
3306/// printf ::= 'printf(' exp exp StringLit exp* ')' name? info?
3307ParseResult FIRStmtParser::parsePrintf() {
3308 auto startTok = consumeToken(FIRToken::lp_printf);
3309
3310 Value clock, condition;
3311 StringRef formatString;
3312 if (parseExp(clock, "expected clock expression in printf") ||
3313 parseToken(FIRToken::comma, "expected ','") ||
3314 parseExp(condition, "expected condition in printf") ||
3315 parseToken(FIRToken::comma, "expected ','"))
3316 return failure();
3317
3318 auto formatStringLoc = getToken().getLoc();
3319 if (parseGetSpelling(formatString) ||
3320 parseToken(FIRToken::string, "expected format string in printf"))
3321 return failure();
3322
3323 SmallVector<Value, 4> specOperands;
3324 while (consumeIf(FIRToken::comma)) {
3325 specOperands.push_back({});
3326 if (parseExp(specOperands.back(), "expected operand in printf"))
3327 return failure();
3328 }
3329
3330 StringAttr name;
3331 if (parseToken(FIRToken::r_paren, "expected ')'") ||
3332 parseOptionalName(name) || parseOptionalInfo())
3333 return failure();
3334
3335 locationProcessor.setLoc(startTok.getLoc());
3336
3337 StringAttr formatStrUnescaped;
3338 SmallVector<Value> operands;
3339 if (parseFormatString(formatStringLoc, formatString, specOperands,
3340 formatStrUnescaped, operands))
3341 return failure();
3342
3343 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3344 name);
3345 return success();
3346}
3347
3348/// fprintf ::= 'fprintf(' exp exp StringLit StringLit exp* ')' name? info?
3349ParseResult FIRStmtParser::parseFPrintf() {
3350 if (requireFeature(nextFIRVersion, "fprintf"))
3351 return failure();
3352 auto startTok = consumeToken(FIRToken::lp_fprintf);
3353
3354 Value clock, condition;
3355 StringRef outputFile, formatString;
3356 if (parseExp(clock, "expected clock expression in fprintf") ||
3357 parseToken(FIRToken::comma, "expected ','") ||
3358 parseExp(condition, "expected condition in fprintf") ||
3359 parseToken(FIRToken::comma, "expected ','"))
3360 return failure();
3361
3362 auto outputFileLoc = getToken().getLoc();
3363 if (parseGetSpelling(outputFile) ||
3364 parseToken(FIRToken::string, "expected output file in fprintf"))
3365 return failure();
3366
3367 SmallVector<Value, 4> outputFileSpecOperands;
3368 while (consumeIf(FIRToken::comma)) {
3369 // Stop parsing operands when we see the format string.
3370 if (getToken().getKind() == FIRToken::string)
3371 break;
3372 outputFileSpecOperands.push_back({});
3373 if (parseExp(outputFileSpecOperands.back(), "expected operand in fprintf"))
3374 return failure();
3375 }
3376
3377 auto formatStringLoc = getToken().getLoc();
3378 if (parseGetSpelling(formatString) ||
3379 parseToken(FIRToken::string, "expected format string in printf"))
3380 return failure();
3381
3382 SmallVector<Value, 4> specOperands;
3383 while (consumeIf(FIRToken::comma)) {
3384 specOperands.push_back({});
3385 if (parseExp(specOperands.back(), "expected operand in fprintf"))
3386 return failure();
3387 }
3388
3389 StringAttr name;
3390 if (parseToken(FIRToken::r_paren, "expected ')'") ||
3391 parseOptionalName(name) || parseOptionalInfo())
3392 return failure();
3393
3394 locationProcessor.setLoc(startTok.getLoc());
3395
3396 StringAttr outputFileNameStrUnescaped;
3397 SmallVector<Value> outputFileOperands;
3398 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3399 outputFileNameStrUnescaped, outputFileOperands))
3400 return failure();
3401
3402 StringAttr formatStrUnescaped;
3403 SmallVector<Value> operands;
3404 if (parseFormatString(formatStringLoc, formatString, specOperands,
3405 formatStrUnescaped, operands))
3406 return failure();
3407
3408 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3409 outputFileOperands, formatStrUnescaped, operands, name);
3410 return success();
3411}
3412
3413/// fflush ::= 'fflush(' exp exp (StringLit exp*)? ')' info?
3414ParseResult FIRStmtParser::parseFFlush() {
3415 if (requireFeature(nextFIRVersion, "fflush"))
3416 return failure();
3417
3418 auto startTok = consumeToken(FIRToken::lp_fflush);
3419
3420 Value clock, condition;
3421 if (parseExp(clock, "expected clock expression in 'fflush'") ||
3422 parseToken(FIRToken::comma, "expected ','") ||
3423 parseExp(condition, "expected condition in 'fflush'"))
3424 return failure();
3425
3426 locationProcessor.setLoc(startTok.getLoc());
3427 StringAttr outputFileNameStrUnescaped;
3428 SmallVector<Value> outputFileOperands;
3429 // Parse file name if present.
3430 if (consumeIf(FIRToken::comma)) {
3431 SmallVector<Value, 4> outputFileSpecOperands;
3432 auto outputFileLoc = getToken().getLoc();
3433 StringRef outputFile;
3434 if (parseGetSpelling(outputFile) ||
3435 parseToken(FIRToken::string, "expected output file in fflush"))
3436 return failure();
3437
3438 while (consumeIf(FIRToken::comma)) {
3439 outputFileSpecOperands.push_back({});
3440 if (parseExp(outputFileSpecOperands.back(), "expected operand in fflush"))
3441 return failure();
3442 }
3443
3444 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3445 outputFileNameStrUnescaped, outputFileOperands))
3446 return failure();
3447 }
3448
3449 if (parseToken(FIRToken::r_paren, "expected ')' in 'fflush'") ||
3450 parseOptionalInfo())
3451 return failure();
3452
3453 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3454 outputFileOperands);
3455 return success();
3456}
3457
3458/// skip ::= 'skip' info?
3459ParseResult FIRStmtParser::parseSkip() {
3460 auto startTok = consumeToken(FIRToken::kw_skip);
3461
3462 // If this was actually the start of a connect or something else handle
3463 // that.
3464 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3465 return *isExpr;
3466
3467 if (parseOptionalInfo())
3468 return failure();
3469
3470 locationProcessor.setLoc(startTok.getLoc());
3471 SkipOp::create(builder);
3472 return success();
3473}
3474
3475/// stop ::= 'stop(' exp exp intLit ')' info?
3476ParseResult FIRStmtParser::parseStop() {
3477 auto startTok = consumeToken(FIRToken::lp_stop);
3478
3479 Value clock, condition;
3480 int64_t exitCode;
3481 StringAttr name;
3482 if (parseExp(clock, "expected clock expression in 'stop'") ||
3483 parseToken(FIRToken::comma, "expected ','") ||
3484 parseExp(condition, "expected condition in 'stop'") ||
3485 parseToken(FIRToken::comma, "expected ','") ||
3486 parseIntLit(exitCode, "expected exit code in 'stop'") ||
3487 parseToken(FIRToken::r_paren, "expected ')' in 'stop'") ||
3488 parseOptionalName(name) || parseOptionalInfo())
3489 return failure();
3490
3491 locationProcessor.setLoc(startTok.getLoc());
3492 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3493 name);
3494 return success();
3495}
3496
3497/// assert ::= 'assert(' exp exp exp StringLit exp*')' info?
3498ParseResult FIRStmtParser::parseAssert() {
3499 auto startTok = consumeToken(FIRToken::lp_assert);
3500
3501 Value clock, predicate, enable;
3502 StringRef formatString;
3503 StringAttr name;
3504 if (parseExp(clock, "expected clock expression in 'assert'") ||
3505 parseToken(FIRToken::comma, "expected ','") ||
3506 parseExp(predicate, "expected predicate in 'assert'") ||
3507 parseToken(FIRToken::comma, "expected ','") ||
3508 parseExp(enable, "expected enable in 'assert'") ||
3509 parseToken(FIRToken::comma, "expected ','") ||
3510 parseGetSpelling(formatString) ||
3511 parseToken(FIRToken::string, "expected format string in 'assert'"))
3512 return failure();
3513
3514 SmallVector<Value, 4> operands;
3515 while (!consumeIf(FIRToken::r_paren)) {
3516 operands.push_back({});
3517 if (parseToken(FIRToken::comma, "expected ','") ||
3518 parseExp(operands.back(), "expected operand in 'assert'"))
3519 return failure();
3520 }
3521
3522 if (parseOptionalName(name) || parseOptionalInfo())
3523 return failure();
3524
3525 locationProcessor.setLoc(startTok.getLoc());
3526 auto formatStrUnescaped = FIRToken::getStringValue(formatString);
3527 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3528 operands, name.getValue());
3529 return success();
3530}
3531
3532/// assume ::= 'assume(' exp exp exp StringLit exp* ')' info?
3533ParseResult FIRStmtParser::parseAssume() {
3534 auto startTok = consumeToken(FIRToken::lp_assume);
3535
3536 Value clock, predicate, enable;
3537 StringRef formatString;
3538 StringAttr name;
3539 if (parseExp(clock, "expected clock expression in 'assume'") ||
3540 parseToken(FIRToken::comma, "expected ','") ||
3541 parseExp(predicate, "expected predicate in 'assume'") ||
3542 parseToken(FIRToken::comma, "expected ','") ||
3543 parseExp(enable, "expected enable in 'assume'") ||
3544 parseToken(FIRToken::comma, "expected ','") ||
3545 parseGetSpelling(formatString) ||
3546 parseToken(FIRToken::string, "expected format string in 'assume'"))
3547 return failure();
3548
3549 SmallVector<Value, 4> operands;
3550 while (!consumeIf(FIRToken::r_paren)) {
3551 operands.push_back({});
3552 if (parseToken(FIRToken::comma, "expected ','") ||
3553 parseExp(operands.back(), "expected operand in 'assume'"))
3554 return failure();
3555 }
3556
3557 if (parseOptionalName(name) || parseOptionalInfo())
3558 return failure();
3559
3560 locationProcessor.setLoc(startTok.getLoc());
3561 auto formatStrUnescaped = FIRToken::getStringValue(formatString);
3562 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3563 operands, name.getValue());
3564 return success();
3565}
3566
3567/// cover ::= 'cover(' exp exp exp StringLit ')' info?
3568ParseResult FIRStmtParser::parseCover() {
3569 auto startTok = consumeToken(FIRToken::lp_cover);
3570
3571 Value clock, predicate, enable;
3572 StringRef message;
3573 StringAttr name;
3574 if (parseExp(clock, "expected clock expression in 'cover'") ||
3575 parseToken(FIRToken::comma, "expected ','") ||
3576 parseExp(predicate, "expected predicate in 'cover'") ||
3577 parseToken(FIRToken::comma, "expected ','") ||
3578 parseExp(enable, "expected enable in 'cover'") ||
3579 parseToken(FIRToken::comma, "expected ','") ||
3580 parseGetSpelling(message) ||
3581 parseToken(FIRToken::string, "expected message in 'cover'") ||
3582 parseToken(FIRToken::r_paren, "expected ')' in 'cover'") ||
3583 parseOptionalName(name) || parseOptionalInfo())
3584 return failure();
3585
3586 locationProcessor.setLoc(startTok.getLoc());
3587 auto messageUnescaped = FIRToken::getStringValue(message);
3588 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3589 ValueRange{}, name.getValue());
3590 return success();
3591}
3592
3593/// when ::= 'when' exp ':' info? suite? ('else' ( when | ':' info? suite?)
3594/// )? suite ::= simple_stmt | INDENT simple_stmt+ DEDENT
3595ParseResult FIRStmtParser::parseWhen(unsigned whenIndent) {
3596 auto startTok = consumeToken(FIRToken::kw_when);
3597
3598 // If this was actually the start of a connect or something else handle
3599 // that.
3600 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3601 return *isExpr;
3602
3603 Value condition;
3604 if (parseExp(condition, "expected condition in 'when'") ||
3605 parseToken(FIRToken::colon, "expected ':' in when") ||
3606 parseOptionalInfo())
3607 return failure();
3608
3609 locationProcessor.setLoc(startTok.getLoc());
3610 // Create the IR representation for the when.
3611 auto whenStmt = WhenOp::create(builder, condition, /*createElse*/ false);
3612
3613 // Parse the 'then' body into the 'then' region.
3614 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3615 return failure();
3616
3617 // If the else is present, handle it otherwise we're done.
3618 if (getToken().isNot(FIRToken::kw_else))
3619 return success();
3620
3621 // If the 'else' is less indented than the when, then it must belong to some
3622 // containing 'when'.
3623 auto elseIndent = getIndentation();
3624 if (elseIndent && *elseIndent < whenIndent)
3625 return success();
3626
3627 consumeToken(FIRToken::kw_else);
3628
3629 // Create an else block to parse into.
3630 whenStmt.createElseRegion();
3631
3632 // If we have the ':' form, then handle it.
3633
3634 // Syntactic shorthand 'else when'. This uses the same indentation level as
3635 // the outer 'when'.
3636 if (getToken().is(FIRToken::kw_when)) {
3637 // We create a sub parser for the else block.
3638 auto subParser = std::make_unique<FIRStmtParser>(
3639 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3640 version, layerSym);
3641
3642 return subParser->parseSimpleStmt(whenIndent);
3643 }
3644
3645 // Parse the 'else' body into the 'else' region.
3646 LocationAttr elseLoc; // ignore the else locator.
3647 if (parseToken(FIRToken::colon, "expected ':' after 'else'") ||
3648 parseOptionalInfoLocator(elseLoc) ||
3649 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3650 return failure();
3651
3652 // TODO(firrtl spec): There is no reason for the 'else :' grammar to take an
3653 // info. It doesn't appear to be generated either.
3654 return success();
3655}
3656
3657/// enum-exp ::= enum-type '(' Id ( ',' exp )? ')'
3658ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3659 auto startLoc = getToken().getLoc();
3660 locationProcessor.setLoc(startLoc);
3661 FIRRTLType type;
3662 if (parseEnumType(type))
3663 return failure();
3664
3665 // Check that the input type is a legal enumeration.
3666 auto enumType = type_dyn_cast<FEnumType>(type);
3667 if (!enumType)
3668 return emitError(startLoc,
3669 "expected enumeration type in enumeration expression");
3670
3671 StringRef tag;
3672 if (parseToken(FIRToken::l_paren, "expected '(' in enumeration expression") ||
3673 parseId(tag, "expected enumeration tag"))
3674 return failure();
3675
3676 Value input;
3677 if (consumeIf(FIRToken::r_paren)) {
3678 // If the payload is not specified, we create a 0 bit unsigned integer
3679 // constant.
3680 auto type = IntType::get(builder.getContext(), false, 0, true);
3681 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3682 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0, false));
3683 input = ConstantOp::create(builder, type, attr);
3684 } else {
3685 // Otherwise we parse an expression.
3686 if (parseToken(FIRToken::comma, "expected ','") ||
3687 parseExp(input, "expected expression in enumeration value") ||
3688 parseToken(FIRToken::r_paren, "expected closing ')'"))
3689 return failure();
3690 }
3691
3692 value = FEnumCreateOp::create(builder, enumType, tag, input);
3693 return success();
3694}
3695
3696/// match ::= 'match' exp ':' info?
3697/// (INDENT ( Id ( '(' Id ')' )? ':'
3698/// (INDENT simple_stmt* DEDENT )?
3699/// )* DEDENT)?
3700ParseResult FIRStmtParser::parseMatch(unsigned matchIndent) {
3701 auto startTok = consumeToken(FIRToken::kw_match);
3702
3703 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3704 return *isExpr;
3705
3706 Value input;
3707 if (parseExp(input, "expected expression in 'match'") ||
3708 parseToken(FIRToken::colon, "expected ':' in 'match'") ||
3709 parseOptionalInfo())
3710 return failure();
3711
3712 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3713 if (!enumType)
3714 return mlir::emitError(
3715 input.getLoc(),
3716 "expected enumeration type for 'match' statement, but got ")
3717 << input.getType();
3718
3719 locationProcessor.setLoc(startTok.getLoc());
3720
3721 SmallVector<Attribute> tags;
3722 SmallVector<std::unique_ptr<Region>> regions;
3723 while (true) {
3724 auto tagLoc = getToken().getLoc();
3725
3726 // Only consume the keyword if the indentation is correct.
3727 auto caseIndent = getIndentation();
3728 if (!caseIndent || *caseIndent <= matchIndent)
3729 break;
3730
3731 // Parse the tag.
3732 StringRef tagSpelling;
3733 if (parseId(tagSpelling, "expected enumeration tag in match statement"))
3734 return failure();
3735 auto tagIndex = enumType.getElementIndex(tagSpelling);
3736 if (!tagIndex)
3737 return emitError(tagLoc, "tag ")
3738 << tagSpelling << " not a member of enumeration " << enumType;
3739 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3740 tags.push_back(tag);
3741
3742 // Add a new case to the match operation.
3743 auto *caseBlock = &regions.emplace_back(new Region)->emplaceBlock();
3744
3745 // Declarations are scoped to the case.
3746 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3747
3748 // After parsing the region, we can release any new entries in
3749 // unbundledValues since the symbol table entries that refer to them will be
3750 // gone.
3751 UnbundledValueRestorer x(moduleContext.unbundledValues);
3752
3753 // Parse the argument.
3754 if (consumeIf(FIRToken::l_paren)) {
3755 StringAttr identifier;
3756 if (parseId(identifier, "expected identifier for 'case' binding"))
3757 return failure();
3758
3759 // Add an argument to the block.
3760 auto dataType = enumType.getElementType(*tagIndex);
3761 caseBlock->addArgument(dataType, LocWithInfo(tagLoc, this).getLoc());
3762
3763 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3764 startTok.getLoc()))
3765 return failure();
3766
3767 if (parseToken(FIRToken::r_paren, "expected ')' in match statement case"))
3768 return failure();
3769
3770 } else {
3771 auto dataType = IntType::get(builder.getContext(), false, 0);
3772 caseBlock->addArgument(dataType, LocWithInfo(tagLoc, this).getLoc());
3773 }
3774
3775 if (parseToken(FIRToken::colon, "expected ':' in match statement case"))
3776 return failure();
3777
3778 // Parse a block of statements that are indented more than the case.
3779 auto subParser = std::make_unique<FIRStmtParser>(
3780 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3781 layerSym);
3782 if (subParser->parseSimpleStmtBlock(*caseIndent))
3783 return failure();
3784 }
3785
3786 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3787 return success();
3788}
3789
3790/// domain_exp ::= id
3791/// domain_exp ::= domain_exp '.' id
3792/// domain_exp ::= domain_exp '[' int ']'
3793ParseResult FIRStmtParser::parseDomainExp(Value &result) {
3794 auto loc = getToken().getLoc();
3795 SymbolValueEntry entry;
3796 StringRef id;
3797 if (parseId(id, "expected domain expression") ||
3798 moduleContext.lookupSymbolEntry(entry, id, loc))
3799 return failure();
3800
3801 if (moduleContext.resolveSymbolEntry(result, entry, loc, false)) {
3802 StringRef field;
3803 if (parseToken(FIRToken::period, "expected '.' in field reference") ||
3804 parseFieldId(field, "expected field name") ||
3805 moduleContext.resolveSymbolEntry(result, entry, field, loc))
3806 return failure();
3807 }
3808
3809 if (parseOptionalExpPostscript(result, /*allowDynamic=*/false))
3810 return failure();
3811
3812 auto type = result.getType();
3813 if (!type_isa<DomainType>(type))
3814 return emitError(loc) << "expected domain-type expression, got " << type;
3815
3816 return success();
3817}
3818
3819/// ref_expr ::= probe | rwprobe | static_reference
3820// NOLINTNEXTLINE(misc-no-recursion)
3821ParseResult FIRStmtParser::parseRefExp(Value &result, const Twine &message) {
3822 auto token = getToken().getKind();
3823 if (token == FIRToken::lp_probe)
3824 return parseProbe(result);
3825 if (token == FIRToken::lp_rwprobe)
3826 return parseRWProbe(result);
3827
3828 // Default to parsing as static reference expression.
3829 // Don't check token kind, we need to support literal_identifier and keywords,
3830 // let parseId handle this.
3831 return parseStaticRefExp(result, message);
3832}
3833
3834/// static_reference ::= id
3835/// ::= static_reference '.' id
3836/// ::= static_reference '[' int ']'
3837// NOLINTNEXTLINE(misc-no-recursion)
3838ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3839 const Twine &message) {
3840 auto parseIdOrInstance = [&]() -> ParseResult {
3841 StringRef id;
3842 auto loc = getToken().getLoc();
3843 SymbolValueEntry symtabEntry;
3844 if (parseId(id, message) ||
3845 moduleContext.lookupSymbolEntry(symtabEntry, id, loc))
3846 return failure();
3847
3848 // If we looked up a normal value, then we're done.
3849 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc, false))
3850 return success();
3851
3852 assert(isa<UnbundledID>(symtabEntry) && "should be an instance");
3853
3854 // Handle the normal "instance.x" reference.
3855 StringRef fieldName;
3856 return failure(
3857 parseToken(FIRToken::period, "expected '.' in field reference") ||
3858 parseFieldId(fieldName, "expected field name") ||
3859 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3860 };
3861 return failure(parseIdOrInstance() ||
3862 parseOptionalExpPostscript(result, false));
3863}
3864/// static_reference ::= id
3865/// ::= static_reference '.' id
3866/// ::= static_reference '[' int ']'
3867/// Populate `refResult` with rwprobe "root" and parsed indexing.
3868/// Root is base-type target, and will be block argument or forceable.
3869/// Also set `Type`, so we can handle const-ness while visiting.
3870/// If root is an unbundled entry, replace with bounce wire and update
3871/// the unbundled entry to point to this for future users.
3872// NOLINTNEXTLINE(misc-no-recursion)
3873ParseResult FIRStmtParser::parseRWProbeStaticRefExp(FieldRef &refResult,
3874 Type &type,
3875 const Twine &message) {
3876 auto loc = getToken().getLoc();
3877
3878 StringRef id;
3879 SymbolValueEntry symtabEntry;
3880 if (parseId(id, message) ||
3881 moduleContext.lookupSymbolEntry(symtabEntry, id, loc))
3882 return failure();
3883
3884 // Three kinds of rwprobe targets:
3885 // 1. Instance result. Replace with a forceable wire, handle as (2).
3886 // 2. Forceable declaration.
3887 // 3. BlockArgument.
3888
3889 // We use inner symbols for all.
3890
3891 // Figure out what we have, and parse indexing.
3892 Value result;
3893 if (auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3894 // This means we have an instance.
3895 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3896
3897 StringRef fieldName;
3898 auto loc = getToken().getLoc();
3899 if (parseToken(FIRToken::period, "expected '.' in field reference") ||
3900 parseFieldId(fieldName, "expected field name"))
3901 return failure();
3902
3903 // Find unbundled entry for the specified result/port.
3904 // Get a reference to it--as we may update it (!!).
3905 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3906 for (auto &elt : ubEntry) {
3907 if (elt.first == fieldAttr) {
3908 // Grab the unbundled entry /by reference/ so we can update it with the
3909 // new forceable wire we insert (if not already done).
3910 auto &instResult = elt.second;
3911
3912 // If it's already forceable, use that.
3913 auto *defining = instResult.getDefiningOp();
3914 assert(defining);
3915 if (isa<WireOp>(defining)) {
3916 result = instResult;
3917 break;
3918 }
3919
3920 // Otherwise, replace with bounce wire.
3921 auto type = instResult.getType();
3922
3923 // Create bounce wire for the instance result.
3924 // This may be an open aggregate, or other non-base type.
3925 auto annotations = getConstants().emptyArrayAttr;
3926 StringAttr sym = {};
3927 SmallString<64> name;
3928 (id + "_" + fieldName + "_bounce").toVector(name);
3929 locationProcessor.setLoc(loc);
3930 OpBuilder::InsertionGuard guard(builder);
3931 builder.setInsertionPoint(defining);
3932 auto bounce =
3933 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
3934 annotations, sym);
3935 auto bounceVal = bounce.getDataRaw();
3936
3937 // Replace instance result with reads from bounce wire.
3938 instResult.replaceAllUsesWith(bounceVal);
3939
3940 // Connect to/from the result per flow.
3941 builder.setInsertionPointAfter(defining);
3942 if (foldFlow(instResult) == Flow::Source)
3943 emitConnect(builder, bounceVal, instResult);
3944 else
3945 emitConnect(builder, instResult, bounceVal);
3946 // Set the parse result AND update `instResult` which is a reference to
3947 // the unbundled entry for the instance result, so that future uses also
3948 // find this new wire.
3949 result = instResult = bounce.getDataRaw();
3950 break;
3951 }
3952 }
3953
3954 if (!result) {
3955 emitError(loc, "use of invalid field name '")
3956 << fieldName << "' on bundle value";
3957 return failure();
3958 }
3959 } else {
3960 // This target can be a port or a regular value.
3961 result = cast<Value>(symtabEntry);
3962 }
3963
3964 assert(result);
3965 assert(isa<BlockArgument>(result) ||
3966 result.getDefiningOp<hw::InnerSymbolOpInterface>());
3967
3968 // We have our root value, we just need to parse the field id.
3969 // Build up the FieldRef as processing indexing expressions, and
3970 // compute the type so that we know the const-ness of the final expression.
3971 refResult = FieldRef(result, 0);
3972 type = result.getType();
3973 while (true) {
3974 if (consumeIf(FIRToken::period)) {
3975 SmallVector<StringRef, 3> fields;
3976 if (parseFieldIdSeq(fields, "expected field name"))
3977 return failure();
3978 for (auto fieldName : fields) {
3979 if (auto bundle = type_dyn_cast<BundleType>(type)) {
3980 if (auto index = bundle.getElementIndex(fieldName)) {
3981 refResult = refResult.getSubField(bundle.getFieldID(*index));
3982 type = bundle.getElementTypePreservingConst(*index);
3983 continue;
3984 }
3985 } else if (auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3986 if (auto index = bundle.getElementIndex(fieldName)) {
3987 refResult = refResult.getSubField(bundle.getFieldID(*index));
3988 type = bundle.getElementTypePreservingConst(*index);
3989 continue;
3990 }
3991 } else {
3992 return emitError(loc, "subfield requires bundle operand")
3993 << "got " << type << "\n";
3994 }
3995 return emitError(loc,
3996 "unknown field '" + fieldName + "' in bundle type ")
3997 << type;
3998 }
3999 continue;
4000 }
4001 if (consumeIf(FIRToken::l_square)) {
4002 auto loc = getToken().getLoc();
4003 int32_t index;
4004 if (parseIntLit(index, "expected index") ||
4005 parseToken(FIRToken::r_square, "expected ']'"))
4006 return failure();
4007
4008 if (index < 0)
4009 return emitError(loc, "invalid index specifier");
4010
4011 if (auto vector = type_dyn_cast<FVectorType>(type)) {
4012 if ((unsigned)index < vector.getNumElements()) {
4013 refResult = refResult.getSubField(vector.getFieldID(index));
4014 type = vector.getElementTypePreservingConst();
4015 continue;
4016 }
4017 } else if (auto vector = type_dyn_cast<OpenVectorType>(type)) {
4018 if ((unsigned)index < vector.getNumElements()) {
4019 refResult = refResult.getSubField(vector.getFieldID(index));
4020 type = vector.getElementTypePreservingConst();
4021 continue;
4022 }
4023 } else {
4024 return emitError(loc, "subindex requires vector operand");
4025 }
4026 return emitError(loc, "out of range index '")
4027 << index << "' for vector type " << type;
4028 }
4029 return success();
4030 }
4031}
4032
4033/// intrinsic_expr ::= 'intrinsic(' Id (params)? ':' type exp* ')'
4034/// intrinsic_stmt ::= 'intrinsic(' Id (params)? (':' type )? exp* ')'
4035ParseResult FIRStmtParser::parseIntrinsic(Value &result, bool isStatement) {
4036 auto startTok = consumeToken(FIRToken::lp_intrinsic);
4037 StringRef intrinsic;
4038 ArrayAttr parameters;
4039 FIRRTLType type;
4040
4041 if (parseId(intrinsic, "expected intrinsic identifier") ||
4042 parseOptionalParams(parameters))
4043 return failure();
4044
4045 if (consumeIf(FIRToken::colon)) {
4046 if (parseType(type, "expected intrinsic return type"))
4047 return failure();
4048 } else if (!isStatement)
4049 return emitError("expected ':' in intrinsic expression");
4050
4051 SmallVector<Value> operands;
4052 auto loc = startTok.getLoc();
4053 if (consumeIf(FIRToken::comma)) {
4054 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4055 Value operand;
4056 if (parseExp(operand, "expected operand in intrinsic"))
4057 return failure();
4058 operands.push_back(operand);
4059 locationProcessor.setLoc(loc);
4060 return success();
4061 }))
4062 return failure();
4063 } else {
4064 if (parseToken(FIRToken::r_paren, "expected ')' in intrinsic"))
4065 return failure();
4066 }
4067
4068 if (isStatement)
4069 if (parseOptionalInfo())
4070 return failure();
4071
4072 locationProcessor.setLoc(loc);
4073
4074 auto op = GenericIntrinsicOp::create(
4075 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
4076 if (type)
4077 result = op.getResult();
4078 return success();
4079}
4080
4081/// params ::= '<' param','* '>'
4082ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
4083 if (!consumeIf(FIRToken::less))
4084 return success();
4085
4086 SmallVector<Attribute, 8> parameters;
4087 SmallPtrSet<StringAttr, 8> seen;
4088 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
4089 StringAttr name;
4090 Attribute value;
4091 SMLoc loc;
4092 if (parseParameter(name, value, loc))
4093 return failure();
4094 auto typedValue = dyn_cast<TypedAttr>(value);
4095 if (!typedValue)
4096 return emitError(loc)
4097 << "invalid value for parameter '" << name.getValue() << "'";
4098 if (!seen.insert(name).second)
4099 return emitError(loc, "redefinition of parameter '" +
4100 name.getValue() + "'");
4101 parameters.push_back(ParamDeclAttr::get(name, typedValue));
4102 return success();
4103 }))
4104 return failure();
4105
4106 resultParameters = ArrayAttr::get(getContext(), parameters);
4107 return success();
4108}
4109
4110/// path ::= 'path(' StringLit ')'
4111// NOLINTNEXTLINE(misc-no-recursion)
4112ParseResult FIRStmtParser::parsePathExp(Value &result) {
4113 auto startTok = consumeToken(FIRToken::lp_path);
4114 locationProcessor.setLoc(startTok.getLoc());
4115 StringRef target;
4116 if (parseGetSpelling(target) ||
4117 parseToken(FIRToken::string,
4118 "expected target string in path expression") ||
4119 parseToken(FIRToken::r_paren, "expected ')' in path expression"))
4120 return failure();
4121 result = UnresolvedPathOp::create(
4122 builder, StringAttr::get(getContext(), FIRToken::getStringValue(target)));
4123 return success();
4124}
4125
4126/// domain_instantiation ::= 'domain' id 'of' id ('(' exp (',' exp)* ')')? info?
4127ParseResult FIRStmtParser::parseDomainInstantiation() {
4128 auto startTok = consumeToken(FIRToken::kw_domain);
4129 auto startLoc = startTok.getLoc();
4130
4131 // If this was actually the start of a connect or something else handle that.
4132 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4133 return *isExpr;
4134
4135 locationProcessor.setLoc(startTok.getLoc());
4136
4137 StringAttr instanceName;
4138 StringAttr domainKind;
4139
4140 if (requireFeature(missingSpecFIRVersion, "domains", startLoc) ||
4141 parseId(instanceName, "expected domain instance name") ||
4142 parseToken(FIRToken::kw_of, "expected 'of' after domain instance name") ||
4143 parseId(domainKind, "expected domain type name"))
4144 return failure();
4145
4146 // Create the domain instance
4147 // Look up the domain to get its fields
4148 const auto &domainMap = getConstants().domainMap;
4149 auto lookup = domainMap.find(domainKind.getValue());
4150 if (lookup == domainMap.end())
4151 return emitError(startTok.getLoc())
4152 << "unknown domain '" << domainKind.getValue() << "'";
4153
4154 auto domainType = DomainType::getFromDomainOp(lookup->second);
4155
4156 // Parse optional field values
4157 SmallVector<Value> fieldValues;
4158 if (consumeIf(FIRToken::l_paren)) {
4159 // Parse comma-separated list of expressions
4160 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4161 Value value;
4162 if (parseExp(value, "expected field value expression"))
4163 return failure();
4164 fieldValues.push_back(value);
4165 return success();
4166 }))
4167 return failure();
4168 }
4169
4170 if (parseOptionalInfo())
4171 return failure();
4172
4173 locationProcessor.setLoc(startLoc);
4174 auto result =
4175 DomainCreateOp::create(builder, domainType, instanceName, fieldValues);
4176
4177 // Add to symbol table
4178 return moduleContext.addSymbolEntry(instanceName.getValue(), result,
4179 startTok.getLoc());
4180}
4181
4182/// domain_define ::= 'domain_define' domain_exp '=' domain_exp info?
4183ParseResult FIRStmtParser::parseDomainDefine() {
4184 auto startTok = consumeToken(FIRToken::kw_domain_define);
4185 auto startLoc = startTok.getLoc();
4186 locationProcessor.setLoc(startLoc);
4187
4188 Value dest, src;
4189 if (requireFeature(missingSpecFIRVersion, "domains", startLoc) ||
4190 parseDomainExp(dest) || parseToken(FIRToken::equal, "expected '='") ||
4191 parseDomainExp(src) || parseOptionalInfo())
4192 return failure();
4193
4194 emitConnect(builder, dest, src);
4195 return success();
4196}
4197
4198/// define ::= 'define' static_reference '=' ref_expr info?
4199ParseResult FIRStmtParser::parseRefDefine() {
4200 auto startTok = consumeToken(FIRToken::kw_define);
4201
4202 Value src, target;
4203 if (parseStaticRefExp(target,
4204 "expected static reference expression in 'define'") ||
4205 parseToken(FIRToken::equal,
4206 "expected '=' after define reference expression") ||
4207 parseRefExp(src, "expected reference expression in 'define'") ||
4208 parseOptionalInfo())
4209 return failure();
4210
4211 // Check reference expressions are of reference type.
4212 if (!type_isa<RefType>(target.getType()))
4213 return emitError(startTok.getLoc(), "expected reference-type expression in "
4214 "'define' target (LHS), got ")
4215 << target.getType();
4216 if (!type_isa<RefType>(src.getType()))
4217 return emitError(startTok.getLoc(), "expected reference-type expression in "
4218 "'define' source (RHS), got ")
4219 << src.getType();
4220
4221 // static_reference doesn't differentiate which can be ref.sub'd, so check
4222 // this explicitly:
4223 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4224 return emitError(startTok.getLoc(),
4225 "cannot define into a sub-element of a reference");
4226
4227 locationProcessor.setLoc(startTok.getLoc());
4228
4229 if (!areTypesRefCastable(target.getType(), src.getType()))
4230 return emitError(startTok.getLoc(), "cannot define reference of type ")
4231 << target.getType() << " with incompatible reference of type "
4232 << src.getType();
4233
4234 emitConnect(builder, target, src);
4235
4236 return success();
4237}
4238
4239/// read ::= '(' ref_expr ')'
4240/// XXX: spec says static_reference, allow ref_expr anyway for read(probe(x)).
4241ParseResult FIRStmtParser::parseRefRead(Value &result) {
4242 auto startTok = consumeToken(FIRToken::lp_read);
4243
4244 Value ref;
4245 if (parseRefExp(ref, "expected reference expression in 'read'") ||
4246 parseToken(FIRToken::r_paren, "expected ')' in 'read'"))
4247 return failure();
4248
4249 locationProcessor.setLoc(startTok.getLoc());
4250
4251 // Check argument is a ref-type value.
4252 if (!type_isa<RefType>(ref.getType()))
4253 return emitError(startTok.getLoc(),
4254 "expected reference-type expression in 'read', got ")
4255 << ref.getType();
4256
4257 result = RefResolveOp::create(builder, ref);
4258
4259 return success();
4260}
4261
4262/// probe ::= 'probe' '(' static_ref ')'
4263ParseResult FIRStmtParser::parseProbe(Value &result) {
4264 auto startTok = consumeToken(FIRToken::lp_probe);
4265
4266 Value staticRef;
4267 if (parseStaticRefExp(staticRef,
4268 "expected static reference expression in 'probe'") ||
4269 parseToken(FIRToken::r_paren, "expected ')' in 'probe'"))
4270 return failure();
4271
4272 locationProcessor.setLoc(startTok.getLoc());
4273
4274 // Check probe expression is base-type.
4275 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4276 return emitError(startTok.getLoc(),
4277 "expected base-type expression in 'probe', got ")
4278 << staticRef.getType();
4279
4280 // Check for other unsupported reference sources.
4281 // TODO: Add to ref.send verifier / inferReturnTypes.
4282 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4283 MemoryDebugPortOp, MemoryPortAccessOp>(
4284 staticRef.getDefiningOp()))
4285 return emitError(startTok.getLoc(), "cannot probe memories or their ports");
4286
4287 result = RefSendOp::create(builder, staticRef);
4288
4289 return success();
4290}
4291
4292/// rwprobe ::= 'rwprobe' '(' static_ref ')'
4293ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4294 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4295
4296 FieldRef staticRef;
4297 Type parsedTargetType;
4298 if (parseRWProbeStaticRefExp(
4299 staticRef, parsedTargetType,
4300 "expected static reference expression in 'rwprobe'") ||
4301 parseToken(FIRToken::r_paren, "expected ')' in 'rwprobe'"))
4302 return failure();
4303
4304 locationProcessor.setLoc(startTok.getLoc());
4305
4306 // Checks:
4307 // Not public port (verifier)
4308
4309 // Check probe expression is base-type.
4310 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4311 if (!targetType)
4312 return emitError(startTok.getLoc(),
4313 "expected base-type expression in 'rwprobe', got ")
4314 << parsedTargetType;
4315
4316 auto root = staticRef.getValue();
4317 auto *definingOp = root.getDefiningOp();
4318
4319 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4320 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4321 return emitError(startTok.getLoc(), "cannot probe memories or their ports");
4322
4323 auto forceableType = firrtl::detail::getForceableResultType(true, targetType);
4324 if (!forceableType)
4325 return emitError(startTok.getLoc(), "cannot force target of type ")
4326 << targetType;
4327
4328 // Create the operation with a placeholder reference and add to fixup list.
4329 auto op = RWProbeOp::create(builder, forceableType,
4330 getConstants().placeholderInnerRef);
4331 innerSymFixups.add(op, getTargetFor(staticRef));
4332 result = op;
4333 return success();
4334}
4335
4336/// force ::= 'force(' exp exp ref_expr exp ')' info?
4337ParseResult FIRStmtParser::parseRefForce() {
4338 auto startTok = consumeToken(FIRToken::lp_force);
4339
4340 Value clock, pred, dest, src;
4341 if (parseExp(clock, "expected clock expression in force") ||
4342 parseToken(FIRToken::comma, "expected ','") ||
4343 parseExp(pred, "expected predicate expression in force") ||
4344 parseToken(FIRToken::comma, "expected ','") ||
4345 parseRefExp(dest, "expected destination reference expression in force") ||
4346 parseToken(FIRToken::comma, "expected ','") ||
4347 parseExp(src, "expected source expression in force") ||
4348 parseToken(FIRToken::r_paren, "expected ')' in force") ||
4349 parseOptionalInfo())
4350 return failure();
4351
4352 // Check reference expression is of reference type.
4353 auto ref = type_dyn_cast<RefType>(dest.getType());
4354 if (!ref || !ref.getForceable())
4355 return emitError(
4356 startTok.getLoc(),
4357 "expected rwprobe-type expression for force destination, got ")
4358 << dest.getType();
4359 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4360 if (!srcBaseType)
4361 return emitError(startTok.getLoc(),
4362 "expected base-type for force source, got ")
4363 << src.getType();
4364 if (!srcBaseType.isPassive())
4365 return emitError(startTok.getLoc(),
4366 "expected passive value for force source, got ")
4367 << srcBaseType;
4368
4369 locationProcessor.setLoc(startTok.getLoc());
4370
4371 // Cast ref to accommodate uninferred sources.
4372 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4373 if (noConstSrcType != ref.getType()) {
4374 // Try to cast destination to rwprobe of source type (dropping const).
4375 auto compatibleRWProbe = RefType::get(noConstSrcType, true, ref.getLayer());
4376 if (areTypesRefCastable(compatibleRWProbe, ref))
4377 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4378 else
4379 return emitError(startTok.getLoc(), "incompatible force source of type ")
4380 << src.getType() << " cannot target destination "
4381 << dest.getType();
4382 }
4383
4384 RefForceOp::create(builder, clock, pred, dest, src);
4385
4386 return success();
4387}
4388
4389/// force_initial ::= 'force_initial(' ref_expr exp ')' info?
4390ParseResult FIRStmtParser::parseRefForceInitial() {
4391 auto startTok = consumeToken(FIRToken::lp_force_initial);
4392
4393 Value dest, src;
4394 if (parseRefExp(
4395 dest, "expected destination reference expression in force_initial") ||
4396 parseToken(FIRToken::comma, "expected ','") ||
4397 parseExp(src, "expected source expression in force_initial") ||
4398 parseToken(FIRToken::r_paren, "expected ')' in force_initial") ||
4399 parseOptionalInfo())
4400 return failure();
4401
4402 // Check reference expression is of reference type.
4403 auto ref = type_dyn_cast<RefType>(dest.getType());
4404 if (!ref || !ref.getForceable())
4405 return emitError(startTok.getLoc(), "expected rwprobe-type expression for "
4406 "force_initial destination, got ")
4407 << dest.getType();
4408 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4409 if (!srcBaseType)
4410 return emitError(startTok.getLoc(),
4411 "expected base-type expression for force_initial "
4412 "source, got ")
4413 << src.getType();
4414 if (!srcBaseType.isPassive())
4415 return emitError(startTok.getLoc(),
4416 "expected passive value for force_initial source, got ")
4417 << srcBaseType;
4418
4419 locationProcessor.setLoc(startTok.getLoc());
4420
4421 // Cast ref to accommodate uninferred sources.
4422 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4423 if (noConstSrcType != ref.getType()) {
4424 // Try to cast destination to rwprobe of source type (dropping const).
4425 auto compatibleRWProbe = RefType::get(noConstSrcType, true, ref.getLayer());
4426 if (areTypesRefCastable(compatibleRWProbe, ref))
4427 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4428 else
4429 return emitError(startTok.getLoc(),
4430 "incompatible force_initial source of type ")
4431 << src.getType() << " cannot target destination "
4432 << dest.getType();
4433 }
4434
4435 auto value = APInt::getAllOnes(1);
4436 auto type = UIntType::get(builder.getContext(), 1);
4437 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4438 value.getBitWidth(),
4439 IntegerType::Unsigned),
4440 value);
4441 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4442 RefForceInitialOp::create(builder, pred, dest, src);
4443
4444 return success();
4445}
4446
4447/// release ::= 'release(' exp exp ref_expr ')' info?
4448ParseResult FIRStmtParser::parseRefRelease() {
4449 auto startTok = consumeToken(FIRToken::lp_release);
4450
4451 Value clock, pred, dest;
4452 if (parseExp(clock, "expected clock expression in release") ||
4453 parseToken(FIRToken::comma, "expected ','") ||
4454 parseExp(pred, "expected predicate expression in release") ||
4455 parseToken(FIRToken::comma, "expected ','") ||
4456 parseRefExp(dest,
4457 "expected destination reference expression in release") ||
4458 parseToken(FIRToken::r_paren, "expected ')' in release") ||
4459 parseOptionalInfo())
4460 return failure();
4461
4462 // Check reference expression is of reference type.
4463 if (auto ref = type_dyn_cast<RefType>(dest.getType());
4464 !ref || !ref.getForceable())
4465 return emitError(
4466 startTok.getLoc(),
4467 "expected rwprobe-type expression for release destination, got ")
4468 << dest.getType();
4469
4470 locationProcessor.setLoc(startTok.getLoc());
4471
4472 RefReleaseOp::create(builder, clock, pred, dest);
4473
4474 return success();
4475}
4476
4477/// release_initial ::= 'release_initial(' ref_expr ')' info?
4478ParseResult FIRStmtParser::parseRefReleaseInitial() {
4479 auto startTok = consumeToken(FIRToken::lp_release_initial);
4480
4481 Value dest;
4482 if (parseRefExp(
4483 dest,
4484 "expected destination reference expression in release_initial") ||
4485 parseToken(FIRToken::r_paren, "expected ')' in release_initial") ||
4486 parseOptionalInfo())
4487 return failure();
4488
4489 // Check reference expression is of reference type.
4490 if (auto ref = type_dyn_cast<RefType>(dest.getType());
4491 !ref || !ref.getForceable())
4492 return emitError(startTok.getLoc(), "expected rwprobe-type expression for "
4493 "release_initial destination, got ")
4494 << dest.getType();
4495
4496 locationProcessor.setLoc(startTok.getLoc());
4497
4498 auto value = APInt::getAllOnes(1);
4499 auto type = UIntType::get(builder.getContext(), 1);
4500 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4501 value.getBitWidth(),
4502 IntegerType::Unsigned),
4503 value);
4504 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4505 RefReleaseInitialOp::create(builder, pred, dest);
4506
4507 return success();
4508}
4509
4510/// connect ::= 'connect' expr expr
4511ParseResult FIRStmtParser::parseConnect() {
4512 auto startTok = consumeToken(FIRToken::kw_connect);
4513 auto loc = startTok.getLoc();
4514
4515 Value lhs, rhs;
4516 if (parseExp(lhs, "expected connect expression") ||
4517 parseToken(FIRToken::comma, "expected ','") ||
4518 parseExp(rhs, "expected connect expression") || parseOptionalInfo())
4519 return failure();
4520
4521 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4522 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4523 if (!lhsType || !rhsType)
4524 return emitError(loc, "cannot connect reference or property types");
4525 // TODO: Once support lands for agg-of-ref, add test for this check!
4526 if (lhsType.containsReference() || rhsType.containsReference())
4527 return emitError(loc, "cannot connect types containing references");
4528
4529 if (!areTypesEquivalent(lhsType, rhsType))
4530 return emitError(loc, "cannot connect non-equivalent type ")
4531 << rhsType << " to " << lhsType;
4532
4533 locationProcessor.setLoc(loc);
4534 emitConnect(builder, lhs, rhs);
4535 return success();
4536}
4537
4538/// propassign ::= 'propassign' expr expr
4539ParseResult FIRStmtParser::parsePropAssign() {
4540 auto startTok = consumeToken(FIRToken::kw_propassign);
4541 auto loc = startTok.getLoc();
4542
4543 Value lhs, rhs;
4544 if (parseExp(lhs, "expected propassign expression") ||
4545 parseToken(FIRToken::comma, "expected ','") ||
4546 parseExp(rhs, "expected propassign expression") || parseOptionalInfo())
4547 return failure();
4548
4549 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4550 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4551 if (!lhsType || !rhsType)
4552 return emitError(loc, "can only propassign property types");
4553 locationProcessor.setLoc(loc);
4554 if (lhsType != rhsType) {
4555 // If the lhs is anyref, and the rhs is a ClassType, insert a cast.
4556 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4557 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4558 else
4559 return emitError(loc, "cannot propassign non-equivalent type ")
4560 << rhsType << " to " << lhsType;
4561 }
4562 PropAssignOp::create(builder, lhs, rhs);
4563 return success();
4564}
4565
4566/// invalidate ::= 'invalidate' expr
4567ParseResult FIRStmtParser::parseInvalidate() {
4568 auto startTok = consumeToken(FIRToken::kw_invalidate);
4569
4570 Value lhs;
4571
4572 StringRef id;
4573 auto loc = getToken().getLoc();
4574 SymbolValueEntry symtabEntry;
4575 if (parseId(id, "expected static reference expression") ||
4576 moduleContext.lookupSymbolEntry(symtabEntry, id, loc))
4577 return failure();
4578
4579 // If we looked up a normal value (e.g., wire, register, or port), then we
4580 // just need to get any optional trailing expression. Invalidate this.
4581 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc, false)) {
4582 if (parseOptionalExpPostscript(lhs, /*allowDynamic=*/false) ||
4583 parseOptionalInfo())
4584 return failure();
4585
4586 locationProcessor.setLoc(startTok.getLoc());
4587 emitInvalidate(lhs);
4588 return success();
4589 }
4590
4591 // We're dealing with an instance. This instance may or may not have a
4592 // trailing expression. Handle the special case of no trailing expression
4593 // first by invalidating all of its results.
4594 assert(isa<UnbundledID>(symtabEntry) && "should be an instance");
4595
4596 if (getToken().isNot(FIRToken::period)) {
4597 locationProcessor.setLoc(loc);
4598 // Invalidate all of the results of the bundled value.
4599 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4600 UnbundledValueEntry &ubEntry = moduleContext.getUnbundledEntry(unbundledId);
4601 for (auto elt : ubEntry)
4602 emitInvalidate(elt.second);
4603 return success();
4604 }
4605
4606 // Handle the case of an instance with a trailing expression. This must begin
4607 // with a '.' (until we add instance arrays).
4608 StringRef fieldName;
4609 if (parseToken(FIRToken::period, "expected '.' in field reference") ||
4610 parseFieldId(fieldName, "expected field name") ||
4611 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4612 return failure();
4613
4614 // Update with any trailing expression and invalidate it.
4615 if (parseOptionalExpPostscript(lhs, /*allowDynamic=*/false) ||
4616 parseOptionalInfo())
4617 return failure();
4618
4619 locationProcessor.setLoc(startTok.getLoc());
4620 emitInvalidate(lhs);
4621 return success();
4622}
4623
4624ParseResult FIRStmtParser::parseLayerBlockOrGroup(unsigned indent) {
4625
4626 auto startTok = consumeToken();
4627 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4628 "consumed an unexpected token");
4629 auto loc = startTok.getLoc();
4630
4631 StringRef id;
4632 if (parseId(id, "expected layer identifer") ||
4633 parseToken(FIRToken::colon, "expected ':' at end of layer block") ||
4634 parseOptionalInfo())
4635 return failure();
4636
4637 locationProcessor.setLoc(loc);
4638
4639 StringRef rootLayer;
4640 SmallVector<FlatSymbolRefAttr> nestedLayers;
4641 if (!layerSym) {
4642 rootLayer = id;
4643 } else {
4644 rootLayer = layerSym.getRootReference();
4645 auto nestedRefs = layerSym.getNestedReferences();
4646 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4647 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(), id));
4648 }
4649
4650 auto layerBlockOp = LayerBlockOp::create(
4651 builder,
4652 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4653 layerBlockOp->getRegion(0).push_back(new Block());
4654
4655 if (getIndentation() > indent)
4656 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4657 layerBlockOp.getLayerName()))
4658 return failure();
4659
4660 return success();
4661}
4662
4663/// leading-exp-stmt ::= exp '<=' exp info?
4664/// ::= exp 'is' 'invalid' info?
4665ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4666 auto loc = getToken().getLoc();
4667
4668 // If 'is' grammar is special.
4669 if (consumeIf(FIRToken::kw_is)) {
4670 if (parseToken(FIRToken::kw_invalid, "expected 'invalid'") ||
4671 parseOptionalInfo())
4672 return failure();
4673
4674 if (removedFeature({3, 0, 0}, "'is invalid' statements", loc))
4675 return failure();
4676
4677 locationProcessor.setLoc(loc);
4678 emitInvalidate(lhs);
4679 return success();
4680 }
4681
4682 if (parseToken(FIRToken::less_equal, "expected '<=' in statement"))
4683 return failure();
4684
4685 if (removedFeature({3, 0, 0}, "'<=' connections", loc))
4686 return failure();
4687
4688 Value rhs;
4689 if (parseExp(rhs, "unexpected token in statement") || parseOptionalInfo())
4690 return failure();
4691
4692 locationProcessor.setLoc(loc);
4693
4694 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4695 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4696 if (!lhsType || !rhsType)
4697 return emitError(loc, "cannot connect reference or property types");
4698 // TODO: Once support lands for agg-of-ref, add test for this check!
4699 if (lhsType.containsReference() || rhsType.containsReference())
4700 return emitError(loc, "cannot connect types containing references");
4701
4702 if (!areTypesEquivalent(lhsType, rhsType))
4703 return emitError(loc, "cannot connect non-equivalent type ")
4704 << rhsType << " to " << lhsType;
4705 emitConnect(builder, lhs, rhs);
4706 return success();
4707}
4708
4709//===-------------------------------
4710// FIRStmtParser Declaration Parsing
4711
4712/// instance ::= 'inst' id 'of' id info?
4713ParseResult FIRStmtParser::parseInstance() {
4714 auto startTok = consumeToken(FIRToken::kw_inst);
4715
4716 // If this was actually the start of a connect or something else handle
4717 // that.
4718 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4719 return *isExpr;
4720
4721 StringRef id;
4722 StringRef moduleName;
4723 if (parseId(id, "expected instance name") ||
4724 parseToken(FIRToken::kw_of, "expected 'of' in instance") ||
4725 parseId(moduleName, "expected module name") || parseOptionalInfo())
4726 return failure();
4727
4728 locationProcessor.setLoc(startTok.getLoc());
4729
4730 // Look up the module that is being referenced.
4731 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4732 if (!referencedModule)
4733 return failure();
4734
4735 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4736
4737 auto annotations = getConstants().emptyArrayAttr;
4738 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4739
4740 hw::InnerSymAttr sym = {};
4741 auto result = InstanceOp::create(
4742 builder, referencedModule, id, NameKindEnum::InterestingName,
4743 annotations.getValue(), portAnnotations, false, false, sym);
4744
4745 // Since we are implicitly unbundling the instance results, we need to keep
4746 // track of the mapping from bundle fields to results in the unbundledValues
4747 // data structure. Build our entry now.
4748 UnbundledValueEntry unbundledValueEntry;
4749 unbundledValueEntry.reserve(modulePorts.size());
4750 for (size_t i = 0, e = modulePorts.size(); i != e; ++i)
4751 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4752
4753 // Add it to unbundledValues and add an entry to the symbol table to remember
4754 // it.
4755 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4756 auto entryId = UnbundledID(moduleContext.unbundledValues.size());
4757 return moduleContext.addSymbolEntry(id, entryId, startTok.getLoc());
4758}
4759
4760/// instance_choice ::=
4761/// 'inst_choice' id 'of' id id info? newline indent ( id "=>" id )+ dedent
4762ParseResult FIRStmtParser::parseInstanceChoice() {
4763 auto startTok = consumeToken(FIRToken::kw_instchoice);
4764 SMLoc loc = startTok.getLoc();
4765
4766 // If this was actually the start of a connect or something else handle that.
4767 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4768 return *isExpr;
4769
4770 if (requireFeature(missingSpecFIRVersion, "option groups/instance choices"))
4771 return failure();
4772
4773 StringRef id;
4774 StringRef defaultModuleName;
4775 StringRef optionGroupName;
4776 if (parseId(id, "expected instance name") ||
4777 parseToken(FIRToken::kw_of, "expected 'of' in instance") ||
4778 parseId(defaultModuleName, "expected module name") ||
4779 parseToken(FIRToken::comma, "expected ','") ||
4780 parseId(optionGroupName, "expected option group name") ||
4781 parseToken(FIRToken::colon, "expected ':' after instchoice") ||
4782 parseOptionalInfo())
4783 return failure();
4784
4785 locationProcessor.setLoc(startTok.getLoc());
4786
4787 // Look up the default module referenced by the instance choice.
4788 // The port lists of all the other referenced modules must match this one.
4789 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4790 if (!defaultModule)
4791 return failure();
4792
4793 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4794
4795 // Find the option group.
4796 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4797 if (!optionGroup)
4798 return emitError(loc,
4799 "use of undefined option group '" + optionGroupName + "'");
4800
4801 auto baseIndent = getIndentation();
4802 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4803 while (getIndentation() == baseIndent) {
4804 StringRef caseId;
4805 StringRef caseModuleName;
4806 if (parseId(caseId, "expected a case identifier") ||
4807 parseToken(FIRToken::equal_greater,
4808 "expected '=> in instance choice definition") ||
4809 parseId(caseModuleName, "expected module name"))
4810 return failure();
4811
4812 auto caseModule = getReferencedModule(loc, caseModuleName);
4813 if (!caseModule)
4814 return failure();
4815
4816 for (const auto &[defaultPort, casePort] :
4817 llvm::zip(modulePorts, caseModule.getPorts())) {
4818 if (defaultPort.name != casePort.name)
4819 return emitError(loc, "instance case module port '")
4820 << casePort.name.getValue()
4821 << "' does not match the default module port '"
4822 << defaultPort.name.getValue() << "'";
4823 if (defaultPort.type != casePort.type)
4824 return emitError(loc, "instance case port '")
4825 << casePort.name.getValue()
4826 << "' type does not match the default module port";
4827 }
4828
4829 auto optionCase =
4830 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4831 if (!optionCase)
4832 return emitError(loc, "use of undefined option case '" + caseId + "'");
4833 caseModules.emplace_back(optionCase, caseModule);
4834 }
4835
4836 auto annotations = getConstants().emptyArrayAttr;
4837 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4838
4839 // Create an instance choice op.
4840 StringAttr sym;
4841 auto result = InstanceChoiceOp::create(
4842 builder, defaultModule, caseModules, id, NameKindEnum::InterestingName,
4843 annotations.getValue(), portAnnotations, sym);
4844
4845 // Un-bundle the ports, identically to the regular instance operation.
4846 UnbundledValueEntry unbundledValueEntry;
4847 unbundledValueEntry.reserve(modulePorts.size());
4848 for (size_t i = 0, e = modulePorts.size(); i != e; ++i)
4849 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4850
4851 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4852 auto entryId = UnbundledID(moduleContext.unbundledValues.size());
4853 return moduleContext.addSymbolEntry(id, entryId, startTok.getLoc());
4854}
4855
4856FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4857 StringRef moduleName) {
4858 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4859 if (!referencedModule) {
4860 emitError(loc,
4861 "use of undefined module name '" + moduleName + "' in instance");
4862 return {};
4863 }
4864 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4865 emitError(loc, "cannot create instance of class '" + moduleName +
4866 "', did you mean object?");
4867 return {};
4868 }
4869 return referencedModule;
4870}
4871
4872/// object ::= 'object' id 'of' id info?
4873ParseResult FIRStmtParser::parseObject() {
4874 auto startTok = consumeToken(FIRToken::kw_object);
4875
4876 // If this was actually the start of a connect or something else handle
4877 // that.
4878 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4879 return *isExpr;
4880
4881 if (requireFeature(missingSpecFIRVersion, "object statements"))
4882 return failure();
4883
4884 StringRef id;
4885 StringRef className;
4886 if (parseId(id, "expected object name") ||
4887 parseToken(FIRToken::kw_of, "expected 'of' in object") ||
4888 parseId(className, "expected class name") || parseOptionalInfo())
4889 return failure();
4890
4891 locationProcessor.setLoc(startTok.getLoc());
4892
4893 // Look up the class that is being referenced.
4894 const auto &classMap = getConstants().classMap;
4895 auto lookup = classMap.find(className);
4896 if (lookup == classMap.end())
4897 return emitError(startTok.getLoc(), "use of undefined class name '" +
4898 className + "' in object");
4899 auto referencedClass = lookup->getSecond();
4900 auto result = ObjectOp::create(builder, referencedClass, id);
4901 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
4902}
4903
4904/// cmem ::= 'cmem' id ':' type info?
4905ParseResult FIRStmtParser::parseCombMem() {
4906 // TODO(firrtl spec) cmem is completely undocumented.
4907 auto startTok = consumeToken(FIRToken::kw_cmem);
4908
4909 // If this was actually the start of a connect or something else handle
4910 // that.
4911 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4912 return *isExpr;
4913
4914 StringRef id;
4915 FIRRTLType type;
4916 if (parseId(id, "expected cmem name") ||
4917 parseToken(FIRToken::colon, "expected ':' in cmem") ||
4918 parseType(type, "expected cmem type") || parseOptionalInfo())
4919 return failure();
4920
4921 locationProcessor.setLoc(startTok.getLoc());
4922
4923 // Transform the parsed vector type into a memory type.
4924 auto vectorType = type_dyn_cast<FVectorType>(type);
4925 if (!vectorType)
4926 return emitError("cmem requires vector type");
4927
4928 auto annotations = getConstants().emptyArrayAttr;
4929 StringAttr sym = {};
4930 auto result = CombMemOp::create(
4931 builder, vectorType.getElementType(), vectorType.getNumElements(), id,
4932 NameKindEnum::InterestingName, annotations, sym);
4933 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
4934}
4935
4936/// smem ::= 'smem' id ':' type ruw? info?
4937ParseResult FIRStmtParser::parseSeqMem() {
4938 // TODO(firrtl spec) smem is completely undocumented.
4939 auto startTok = consumeToken(FIRToken::kw_smem);
4940
4941 // If this was actually the start of a connect or something else handle
4942 // that.
4943 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4944 return *isExpr;
4945
4946 StringRef id;
4947 FIRRTLType type;
4948 RUWBehavior ruw = RUWBehavior::Undefined;
4949
4950 if (parseId(id, "expected smem name") ||
4951 parseToken(FIRToken::colon, "expected ':' in smem") ||
4952 parseType(type, "expected smem type"))
4953 return failure();
4954
4955 if (consumeIf(FIRToken::comma)) {
4956 if (parseRUW(ruw))
4957 return failure();
4958 }
4959
4960 if (parseOptionalInfo()) {
4961 return failure();
4962 }
4963
4964 locationProcessor.setLoc(startTok.getLoc());
4965
4966 // Transform the parsed vector type into a memory type.
4967 auto vectorType = type_dyn_cast<FVectorType>(type);
4968 if (!vectorType)
4969 return emitError("smem requires vector type");
4970
4971 auto annotations = getConstants().emptyArrayAttr;
4972 StringAttr sym = {};
4973 auto result = SeqMemOp::create(
4974 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
4975 id, NameKindEnum::InterestingName, annotations, sym);
4976 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
4977}
4978
4979/// mem ::= 'mem' id ':' info? INDENT memField* DEDENT
4980/// memField ::= 'data-type' '=>' type NEWLINE
4981/// ::= 'depth' '=>' intLit NEWLINE
4982/// ::= 'read-latency' '=>' intLit NEWLINE
4983/// ::= 'write-latency' '=>' intLit NEWLINE
4984/// ::= 'read-under-write' '=>' ruw NEWLINE
4985/// ::= 'reader' '=>' id+ NEWLINE
4986/// ::= 'writer' '=>' id+ NEWLINE
4987/// ::= 'readwriter' '=>' id+ NEWLINE
4988ParseResult FIRStmtParser::parseMem(unsigned memIndent) {
4989 auto startTok = consumeToken(FIRToken::kw_mem);
4990
4991 // If this was actually the start of a connect or something else handle
4992 // that.
4993 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4994 return *isExpr;
4995
4996 StringRef id;
4997 if (parseId(id, "expected mem name") ||
4998 parseToken(FIRToken::colon, "expected ':' in mem") || parseOptionalInfo())
4999 return failure();
5000
5001 FIRRTLType type;
5002 int64_t depth = -1, readLatency = -1, writeLatency = -1;
5003 RUWBehavior ruw = RUWBehavior::Undefined;
5004
5005 SmallVector<std::pair<StringAttr, Type>, 4> ports;
5006
5007 // Parse all the memfield records, which are indented more than the mem.
5008 while (1) {
5009 auto nextIndent = getIndentation();
5010 if (!nextIndent || *nextIndent <= memIndent)
5011 break;
5012
5013 auto spelling = getTokenSpelling();
5014 if (parseToken(FIRToken::identifier, "unexpected token in 'mem'") ||
5015 parseToken(FIRToken::equal_greater, "expected '=>' in 'mem'"))
5016 return failure();
5017
5018 if (spelling == "data-type") {
5019 if (type)
5020 return emitError("'mem' type specified multiple times"), failure();
5021
5022 if (parseType(type, "expected type in data-type declaration"))
5023 return failure();
5024 continue;
5025 }
5026 if (spelling == "depth") {
5027 if (parseIntLit(depth, "expected integer in depth specification"))
5028 return failure();
5029 continue;
5030 }
5031 if (spelling == "read-latency") {
5032 if (parseIntLit(readLatency, "expected integer latency"))
5033 return failure();
5034 continue;
5035 }
5036 if (spelling == "write-latency") {
5037 if (parseIntLit(writeLatency, "expected integer latency"))
5038 return failure();
5039 continue;
5040 }
5041 if (spelling == "read-under-write") {
5042 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
5043 FIRToken::kw_undefined))
5044 return emitError("expected specifier"), failure();
5045
5046 if (parseOptionalRUW(ruw))
5047 return failure();
5048 continue;
5049 }
5050
5051 MemOp::PortKind portKind;
5052 if (spelling == "reader")
5053 portKind = MemOp::PortKind::Read;
5054 else if (spelling == "writer")
5055 portKind = MemOp::PortKind::Write;
5056 else if (spelling == "readwriter")
5057 portKind = MemOp::PortKind::ReadWrite;
5058 else
5059 return emitError("unexpected field in 'mem' declaration"), failure();
5060
5061 StringRef portName;
5062 if (parseId(portName, "expected port name"))
5063 return failure();
5064 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
5065 if (!baseType)
5066 return emitError("unexpected type, must be base type");
5067 ports.push_back({builder.getStringAttr(portName),
5068 MemOp::getTypeForPort(depth, baseType, portKind)});
5069
5070 while (!getIndentation().has_value()) {
5071 if (parseId(portName, "expected port name"))
5072 return failure();
5073 ports.push_back({builder.getStringAttr(portName),
5074 MemOp::getTypeForPort(depth, baseType, portKind)});
5075 }
5076 }
5077
5078 // The FIRRTL dialect requires mems to have at least one port. Since portless
5079 // mems can never be referenced, it is always safe to drop them.
5080 if (ports.empty())
5081 return success();
5082
5083 // Canonicalize the ports into alphabetical order.
5084 // TODO: Move this into MemOp construction/canonicalization.
5085 llvm::array_pod_sort(ports.begin(), ports.end(),
5086 [](const std::pair<StringAttr, Type> *lhs,
5087 const std::pair<StringAttr, Type> *rhs) -> int {
5088 return lhs->first.getValue().compare(
5089 rhs->first.getValue());
5090 });
5091
5092 auto annotations = getConstants().emptyArrayAttr;
5093 SmallVector<Attribute, 4> resultNames;
5094 SmallVector<Type, 4> resultTypes;
5095 SmallVector<Attribute, 4> resultAnnotations;
5096 for (auto p : ports) {
5097 resultNames.push_back(p.first);
5098 resultTypes.push_back(p.second);
5099 resultAnnotations.push_back(annotations);
5100 }
5101
5102 locationProcessor.setLoc(startTok.getLoc());
5103
5104 auto result = MemOp::create(
5105 builder, resultTypes, readLatency, writeLatency, depth, ruw,
5106 builder.getArrayAttr(resultNames), id, NameKindEnum::InterestingName,
5107 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
5108 MemoryInitAttr(), StringAttr());
5109
5110 UnbundledValueEntry unbundledValueEntry;
5111 unbundledValueEntry.reserve(result.getNumResults());
5112 for (size_t i = 0, e = result.getNumResults(); i != e; ++i)
5113 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
5114
5115 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
5116 auto entryID = UnbundledID(moduleContext.unbundledValues.size());
5117 return moduleContext.addSymbolEntry(id, entryID, startTok.getLoc());
5118}
5119
5120/// node ::= 'node' id '=' exp info?
5121ParseResult FIRStmtParser::parseNode() {
5122 auto startTok = consumeToken(FIRToken::kw_node);
5123
5124 // If this was actually the start of a connect or something else handle
5125 // that.
5126 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
5127 return *isExpr;
5128
5129 StringRef id;
5130 Value initializer;
5131 if (parseId(id, "expected node name") ||
5132 parseToken(FIRToken::equal, "expected '=' in node") ||
5133 parseExp(initializer, "expected expression for node") ||
5134 parseOptionalInfo())
5135 return failure();
5136
5137 locationProcessor.setLoc(startTok.getLoc());
5138
5139 // Error out in the following conditions:
5140 //
5141 // 1. Node type is Analog (at the top level)
5142 // 2. Node type is not passive under an optional outer flip
5143 // (analog field is okay)
5144 //
5145 // Note: (1) is more restictive than normal NodeOp verification, but
5146 // this is added to align with the SFC. (2) is less restrictive than
5147 // the SFC to accomodate for situations where the node is something
5148 // weird like a module output or an instance input.
5149 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
5150 auto initializerBaseType =
5151 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
5152 if (type_isa<AnalogType>(initializerType) ||
5153 !(initializerBaseType && initializerBaseType.isPassive())) {
5154 emitError(startTok.getLoc())
5155 << "Node cannot be analog and must be passive or passive under a flip "
5156 << initializer.getType();
5157 return failure();
5158 }
5159
5160 auto annotations = getConstants().emptyArrayAttr;
5161 StringAttr sym = {};
5162
5163 auto result = NodeOp::create(builder, initializer, id,
5164 NameKindEnum::InterestingName, annotations, sym);
5165 return moduleContext.addSymbolEntry(id, result.getResult(),
5166 startTok.getLoc());
5167}
5168
5169/// wire ::= 'wire' id ':' type ('domains' '[' domain_list ']')? info?
5170ParseResult FIRStmtParser::parseWire() {
5171 auto startTok = consumeToken(FIRToken::kw_wire);
5172
5173 // If this was actually the start of a connect or something else handle
5174 // that.
5175 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
5176 return *isExpr;
5177
5178 StringRef id;
5179 FIRRTLType type;
5180 if (parseId(id, "expected wire name") ||
5181 parseToken(FIRToken::colon, "expected ':' in wire") ||
5182 parseType(type, "expected wire type"))
5183 return failure();
5184
5185 // Parse optional domain associations
5186 SmallVector<Value> domains;
5187 if (consumeIf(FIRToken::kw_domains)) {
5188 if (requireFeature(missingSpecFIRVersion, "domains", startTok.getLoc()))
5189 return failure();
5190
5191 if (parseToken(FIRToken::l_square, "expected '[' after 'domains'"))
5192 return failure();
5193
5194 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
5195 StringRef domainName;
5196 auto domainLoc = getToken().getLoc();
5197 if (parseId(domainName, "expected domain name"))
5198 return failure();
5199
5200 // Look up the domain value in the module context
5201 SymbolValueEntry lookup;
5202 if (moduleContext.lookupSymbolEntry(lookup, domainName, domainLoc))
5203 return failure();
5204
5205 // Resolve the symbol table entry to a Value
5206 Value domainValue;
5207 if (moduleContext.resolveSymbolEntry(domainValue, lookup, domainLoc))
5208 return failure();
5209
5210 if (!isa<DomainType>(domainValue.getType()))
5211 return emitError(domainLoc)
5212 << "'" << domainName << "' is not a domain";
5213
5214 domains.push_back(domainValue);
5215 return success();
5216 }))
5217 return failure();
5218 }
5219
5220 if (parseOptionalInfo())
5221 return failure();
5222
5223 locationProcessor.setLoc(startTok.getLoc());
5224
5225 auto annotations = getConstants().emptyArrayAttr;
5226 StringAttr sym = {};
5227
5228 // Names of only-nonHW should be droppable.
5229 auto namekind = isa<PropertyType, RefType>(type)
5230 ? NameKindEnum::DroppableName
5231 : NameKindEnum::InterestingName;
5232
5233 auto result = WireOp::create(builder, type, id, namekind, annotations, sym,
5234 /*forceable=*/false, domains);
5235 return moduleContext.addSymbolEntry(id, result.getResult(),
5236 startTok.getLoc());
5237}
5238
5239/// register ::= 'reg' id ':' type exp ('with' ':' reset_block)? info?
5240///
5241/// reset_block ::= INDENT simple_reset info? NEWLINE DEDENT
5242/// ::= '(' simple_reset ')'
5243///
5244/// simple_reset ::= simple_reset0
5245/// ::= '(' simple_reset0 ')'
5246///
5247/// simple_reset0: 'reset' '=>' '(' exp exp ')'
5248///
5249ParseResult FIRStmtParser::parseRegister(unsigned regIndent) {
5250 auto startTok = consumeToken(FIRToken::kw_reg);
5251
5252 // If this was actually the start of a connect or something else handle
5253 // that.
5254 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
5255 return *isExpr;
5256
5257 StringRef id;
5258 FIRRTLType type;
5259 Value clock;
5260
5261 // TODO(firrtl spec): info? should come after the clock expression before
5262 // the 'with'.
5263 if (parseId(id, "expected reg name") ||
5264 parseToken(FIRToken::colon, "expected ':' in reg") ||
5265 parseType(type, "expected reg type") ||
5266 parseToken(FIRToken::comma, "expected ','") ||
5267 parseExp(clock, "expected expression for register clock"))
5268 return failure();
5269
5270 if (!type_isa<FIRRTLBaseType>(type))
5271 return emitError(startTok.getLoc(), "register must have base type");
5272
5273 // Parse the 'with' specifier if present.
5274 Value resetSignal, resetValue;
5275 if (consumeIf(FIRToken::kw_with)) {
5276 if (removedFeature({3, 0, 0}, "'reg with' registers"))
5277 return failure();
5278
5279 if (parseToken(FIRToken::colon, "expected ':' in reg"))
5280 return failure();
5281
5282 // TODO(firrtl spec): Simplify the grammar for register reset logic.
5283 // Why allow multiple ambiguous parentheses? Why rely on indentation at
5284 // all?
5285
5286 // This implements what the examples have in practice.
5287 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5288
5289 auto indent = getIndentation();
5290 if (!indent || *indent <= regIndent)
5291 if (!hasExtraLParen)
5292 return emitError("expected indented reset specifier in reg"), failure();
5293
5294 if (parseToken(FIRToken::kw_reset, "expected 'reset' in reg") ||
5295 parseToken(FIRToken::equal_greater, "expected => in reset specifier") ||
5296 parseToken(FIRToken::l_paren, "expected '(' in reset specifier") ||
5297 parseExp(resetSignal, "expected expression for reset signal") ||
5298 parseToken(FIRToken::comma, "expected ','"))
5299 return failure();
5300
5301 // The Scala implementation of FIRRTL represents registers without resets
5302 // as a self referential register... and the pretty printer doesn't print
5303 // the right form. Recognize that this is happening and treat it as a
5304 // register without a reset for compatibility.
5305 // TODO(firrtl scala impl): pretty print registers without resets right.
5306 if (getTokenSpelling() == id) {
5307 consumeToken();
5308 if (parseToken(FIRToken::r_paren, "expected ')' in reset specifier"))
5309 return failure();
5310 resetSignal = Value();
5311 } else {
5312 if (parseExp(resetValue, "expected expression for reset value") ||
5313 parseToken(FIRToken::r_paren, "expected ')' in reset specifier"))
5314 return failure();
5315 }
5316
5317 if (hasExtraLParen &&
5318 parseToken(FIRToken::r_paren, "expected ')' in reset specifier"))
5319 return failure();
5320 }
5321
5322 // Finally, handle the last info if present, providing location info for the
5323 // clock expression.
5324 if (parseOptionalInfo())
5325 return failure();
5326
5327 locationProcessor.setLoc(startTok.getLoc());
5328
5329 ArrayAttr annotations = getConstants().emptyArrayAttr;
5330 Value result;
5331 StringAttr sym = {};
5332 if (resetSignal)
5333 result =
5334 RegResetOp::create(builder, type, clock, resetSignal, resetValue, id,
5335 NameKindEnum::InterestingName, annotations, sym)
5336 .getResult();
5337 else
5338 result = RegOp::create(builder, type, clock, id,
5339 NameKindEnum::InterestingName, annotations, sym)
5340 .getResult();
5341 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
5342}
5343
5344/// registerWithReset ::= 'regreset' id ':' type exp exp exp
5345///
5346/// This syntax is only supported in FIRRTL versions >= 3.0.0. Because this
5347/// syntax is only valid for >= 3.0.0, there is no need to check if the leading
5348/// "regreset" is part of an expression with a leading keyword.
5349ParseResult FIRStmtParser::parseRegisterWithReset() {
5350 auto startTok = consumeToken(FIRToken::kw_regreset);
5351
5352 StringRef id;
5353 FIRRTLType type;
5354 Value clock, resetSignal, resetValue;
5355
5356 if (parseId(id, "expected reg name") ||
5357 parseToken(FIRToken::colon, "expected ':' in reg") ||
5358 parseType(type, "expected reg type") ||
5359 parseToken(FIRToken::comma, "expected ','") ||
5360 parseExp(clock, "expected expression for register clock") ||
5361 parseToken(FIRToken::comma, "expected ','") ||
5362 parseExp(resetSignal, "expected expression for register reset") ||
5363 parseToken(FIRToken::comma, "expected ','") ||
5364 parseExp(resetValue, "expected expression for register reset value") ||
5365 parseOptionalInfo())
5366 return failure();
5367
5368 if (!type_isa<FIRRTLBaseType>(type))
5369 return emitError(startTok.getLoc(), "register must have base type");
5370
5371 locationProcessor.setLoc(startTok.getLoc());
5372
5373 auto result =
5374 RegResetOp::create(builder, type, clock, resetSignal, resetValue, id,
5375 NameKindEnum::InterestingName,
5376 getConstants().emptyArrayAttr, StringAttr{})
5377 .getResult();
5378
5379 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
5380}
5381
5382/// contract ::= 'contract' (id,+ '=' exp,+) ':' info? contract_body
5383/// contract_body ::= simple_stmt | INDENT simple_stmt+ DEDENT
5384ParseResult FIRStmtParser::parseContract(unsigned blockIndent) {
5385 if (requireFeature(missingSpecFIRVersion, "contracts"))
5386 return failure();
5387
5388 auto startTok = consumeToken(FIRToken::kw_contract);
5389
5390 // Parse the contract results and expressions.
5391 SmallVector<StringRef> ids;
5392 SmallVector<SMLoc> locs;
5393 SmallVector<Value> values;
5394 SmallVector<Type> types;
5395 if (!consumeIf(FIRToken::colon)) {
5396 auto parseContractId = [&] {
5397 StringRef id;
5398 locs.push_back(getToken().getLoc());
5399 if (parseId(id, "expected contract result name"))
5400 return failure();
5401 ids.push_back(id);
5402 return success();
5403 };
5404 auto parseContractValue = [&] {
5405 Value value;
5406 if (parseExp(value, "expected expression for contract result"))
5407 return failure();
5408 values.push_back(value);
5409 types.push_back(value.getType());
5410 return success();
5411 };
5412 if (parseListUntil(FIRToken::equal, parseContractId) ||
5413 parseListUntil(FIRToken::colon, parseContractValue))
5414 return failure();
5415 }
5416 if (parseOptionalInfo())
5417 return failure();
5418
5419 // Each result must have a corresponding expression assigned.
5420 if (ids.size() != values.size())
5421 return emitError(startTok.getLoc())
5422 << "contract requires same number of results and expressions; got "
5423 << ids.size() << " results and " << values.size()
5424 << " expressions instead";
5425
5426 locationProcessor.setLoc(startTok.getLoc());
5427
5428 // Add block arguments for each result and declare their names in a subscope
5429 // for the contract body.
5430 auto contract = ContractOp::create(builder, types, values);
5431 auto &block = contract.getBody().emplaceBlock();
5432
5433 // Parse the contract body.
5434 {
5435 FIRModuleContext::ContextScope scope(moduleContext, &block);
5436 for (auto [id, loc, type] : llvm::zip(ids, locs, types)) {
5437 auto arg = block.addArgument(type, LocWithInfo(loc, this).getLoc());
5438 if (failed(moduleContext.addSymbolEntry(id, arg, loc)))
5439 return failure();
5440 }
5441 if (getIndentation() > blockIndent)
5442 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5443 return failure();
5444 }
5445
5446 // Declare the results.
5447 for (auto [id, loc, value, result] :
5448 llvm::zip(ids, locs, values, contract.getResults())) {
5449 // Remove previous symbol to avoid duplicates
5450 moduleContext.removeSymbolEntry(id);
5451 if (failed(moduleContext.addSymbolEntry(id, result, loc)))
5452 return failure();
5453 }
5454 return success();
5455}
5456
5457//===----------------------------------------------------------------------===//
5458// FIRCircuitParser
5459//===----------------------------------------------------------------------===//
5460
5461namespace {
5462/// This class implements the outer level of the parser, including things
5463/// like circuit and module.
5464struct FIRCircuitParser : public FIRParser {
5465 explicit FIRCircuitParser(SharedParserConstants &state, FIRLexer &lexer,
5466 ModuleOp mlirModule, FIRVersion version)
5467 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5468
5469 ParseResult
5470 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5471 mlir::TimingScope &ts);
5472
5473private:
5474 /// Extract Annotations from a JSON-encoded Annotation array string and add
5475 /// them to a vector of attributes.
5476 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5477 SmallVectorImpl<Attribute> &attrs);
5478
5479 ParseResult parseToplevelDefinition(CircuitOp circuit, unsigned indent);
5480
5481 ParseResult parseClass(CircuitOp circuit, unsigned indent);
5482 ParseResult parseDomain(CircuitOp circuit, unsigned indent);
5483 ParseResult parseExtClass(CircuitOp circuit, unsigned indent);
5484 ParseResult parseExtModule(CircuitOp circuit, unsigned indent);
5485 ParseResult parseIntModule(CircuitOp circuit, unsigned indent);
5486 ParseResult parseModule(CircuitOp circuit, bool isPublic, unsigned indent);
5487 ParseResult parseFormal(CircuitOp circuit, unsigned indent);
5488 ParseResult parseSimulation(CircuitOp circuit, unsigned indent);
5489 template <class Op>
5490 ParseResult parseFormalLike(CircuitOp circuit, unsigned indent);
5491
5492 ParseResult parseLayerName(SymbolRefAttr &result);
5493 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5494 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5495 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5496 ParseResult parseRequiresSpec(SmallVectorImpl<Attribute> &result);
5497 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5498 ParseResult parseExtModuleAttributesSpec(ArrayAttr &enabledLayers,
5499 ArrayAttr &knownLayers,
5500 ArrayAttr &externalRequirements);
5501
5502 ParseResult parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5503 SmallVectorImpl<SMLoc> &resultPortLocs,
5504 unsigned indent);
5505 ParseResult parseParameterList(ArrayAttr &resultParameters);
5506
5507 ParseResult skipToModuleEnd(unsigned indent);
5508
5509 ParseResult parseTypeDecl();
5510
5511 ParseResult parseOptionDecl(CircuitOp circuit);
5512
5513 ParseResult parseLayer(CircuitOp circuit);
5514
5515 ParseResult resolveDomains(
5516 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
5517 const DenseMap<Attribute, size_t> &nameToIndex,
5518 SmallVectorImpl<Attribute> &domainsByIndex);
5519
5520 ParseResult
5521 parseDomains(SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
5522 const DenseMap<Attribute, size_t> &nameToIndex);
5523
5524 struct DeferredModuleToParse {
5525 FModuleLike moduleOp;
5526 SmallVector<SMLoc> portLocs;
5527 FIRLexerCursor lexerCursor;
5528 unsigned indent;
5529 };
5530
5531 ParseResult parseModuleBody(const SymbolTable &circuitSymTbl,
5532 DeferredModuleToParse &deferredModule,
5533 InnerSymFixups &fixups);
5534
5535 SmallVector<DeferredModuleToParse, 0> deferredModules;
5536
5537 SmallVector<InnerSymFixups, 0> moduleFixups;
5538
5539 hw::InnerSymbolNamespaceCollection innerSymbolNamespaces;
5540
5541 ModuleOp mlirModule;
5542};
5543
5544} // end anonymous namespace
5545ParseResult
5546FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5547 SmallVectorImpl<Attribute> &attrs) {
5548
5549 auto annotations = json::parse(annotationsStr);
5550 if (auto err = annotations.takeError()) {
5551 handleAllErrors(std::move(err), [&](const json::ParseError &a) {
5552 auto diag = emitError(loc, "Failed to parse JSON Annotations");
5553 diag.attachNote() << a.message();
5554 });
5555 return failure();
5556 }
5557
5558 json::Path::Root root;
5559 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5560 if (!importAnnotationsFromJSONRaw(annotations.get(), attrs, root,
5561 getContext())) {
5562 auto diag = emitError(loc, "Invalid/unsupported annotation format");
5563 std::string jsonErrorMessage =
5564 "See inline comments for problem area in JSON:\n";
5565 llvm::raw_string_ostream s(jsonErrorMessage);
5566 root.printErrorContext(annotations.get(), s);
5567 diag.attachNote() << jsonErrorMessage;
5568 return failure();
5569 }
5570
5571 return success();
5572}
5573
5574ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5575 auto *context = getContext();
5576 SmallVector<StringRef> strings;
5577 do {
5578 StringRef name;
5579 if (parseId(name, "expected layer name"))
5580 return failure();
5581 strings.push_back(name);
5582 } while (consumeIf(FIRToken::period));
5583
5584 SmallVector<FlatSymbolRefAttr> nested;
5585 nested.reserve(strings.size() - 1);
5586 for (unsigned i = 1, e = strings.size(); i < e; ++i)
5587 nested.push_back(FlatSymbolRefAttr::get(context, strings[i]));
5588
5589 result = SymbolRefAttr::get(context, strings[0], nested);
5590 return success();
5591}
5592
5593ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5594 SmallVector<Attribute> enabledLayersBuffer;
5595 while (true) {
5596 auto tokenKind = getToken().getKind();
5597 // Parse an enablelayer spec.
5598 if (tokenKind == FIRToken::kw_enablelayer) {
5599 if (parseEnableLayerSpec(enabledLayersBuffer))
5600 return failure();
5601 continue;
5602 }
5603 // Didn't parse a layer spec.
5604 break;
5605 }
5606
5607 if (enabledLayersBuffer.size() != 0)
5608 if (requireFeature({4, 0, 0}, "modules with layers enabled"))
5609 return failure();
5610
5611 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5612 return success();
5613}
5614
5615ParseResult FIRCircuitParser::parseExtModuleAttributesSpec(
5616 ArrayAttr &enabledLayers, ArrayAttr &knownLayers,
5617 ArrayAttr &externalRequirements) {
5618 SmallVector<Attribute> enabledLayersBuffer;
5619 SmallVector<Attribute> knownLayersBuffer;
5620 SmallVector<Attribute> requirementsBuffer;
5621 while (true) {
5622 auto tokenKind = getToken().getKind();
5623 // Parse an enablelayer spec.
5624 if (tokenKind == FIRToken::kw_enablelayer) {
5625 if (parseEnableLayerSpec(enabledLayersBuffer))
5626 return failure();
5627 continue;
5628 }
5629 // Parse a knownlayer spec.
5630 if (tokenKind == FIRToken::kw_knownlayer) {
5631 if (parseKnownLayerSpec(knownLayersBuffer))
5632 return failure();
5633 continue;
5634 }
5635 // Parse a requires spec.
5636 if (tokenKind == FIRToken::kw_requires) {
5637 if (parseRequiresSpec(requirementsBuffer))
5638 return failure();
5639 continue;
5640 }
5641 // Didn't parse a layer spec or requires.
5642 break;
5643 }
5644
5645 if (enabledLayersBuffer.size() != 0)
5646 if (requireFeature({4, 0, 0}, "extmodules with layers enabled"))
5647 return failure();
5648
5649 if (knownLayersBuffer.size() != 0)
5650 if (requireFeature(nextFIRVersion, "extmodules with known layers"))
5651 return failure();
5652
5653 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5654 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5655 externalRequirements = ArrayAttr::get(getContext(), requirementsBuffer);
5656 return success();
5657}
5658
5659ParseResult
5660FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5661 do {
5662 SymbolRefAttr layer;
5663 if (parseLayerName(layer))
5664 return failure();
5665 result.push_back(layer);
5666 } while (consumeIf(FIRToken::comma));
5667 return success();
5668}
5669
5670ParseResult
5671FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5672 consumeToken(FIRToken::kw_enablelayer);
5673 return parseLayerList(result);
5674}
5675
5676ParseResult
5677FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5678 consumeToken(FIRToken::kw_knownlayer);
5679 return parseLayerList(result);
5680}
5681
5682ParseResult
5683FIRCircuitParser::parseRequiresSpec(SmallVectorImpl<Attribute> &result) {
5684 consumeToken(FIRToken::kw_requires);
5685 do {
5686 StringRef requireStr;
5687 if (parseGetSpelling(requireStr) ||
5688 parseToken(FIRToken::string, "expected string after 'requires'"))
5689 return failure();
5690 // Remove the surrounding quotes from the string.
5691 result.push_back(
5692 StringAttr::get(getContext(), requireStr.drop_front().drop_back()));
5693 } while (consumeIf(FIRToken::comma));
5694 return success();
5695}
5696
5697/// portlist ::= port*
5698/// port ::= dir id ':' type info? NEWLINE
5699/// dir ::= 'input' | 'output'
5700ParseResult
5701FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5702 SmallVectorImpl<SMLoc> &resultPortLocs,
5703 unsigned indent) {
5704 // Stores of information about domains as they are parsed:
5705 // 1. Mapping of domain name to port index
5706 // 2. Mapping of port index to domain associations, using domain _names_.
5707 // The locations are recorded to generate good error messages.
5708 DenseMap<Attribute, size_t> nameToIndex;
5709 DenseMap<size_t, SmallVector<std::pair<Attribute, SMLoc>>> domainNames;
5710
5711 // Parse any ports. Populate domain information.
5712 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5713 // Must be nested under the module.
5714 getIndentation() > indent) {
5715
5716 // We need one token lookahead to resolve the ambiguity between:
5717 // output foo ; port
5718 // output <= input ; identifier expression
5719 // output.thing <= input ; identifier expression
5720 auto backtrackState = getLexer().getCursor();
5721
5722 bool isOutput = getToken().is(FIRToken::kw_output);
5723 consumeToken();
5724
5725 // If we have something that isn't a keyword then this must be an
5726 // identifier, not an input/output marker.
5727 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5728 !getToken().isKeyword()) {
5729 backtrackState.restore(getLexer());
5730 break;
5731 }
5732
5733 StringAttr name;
5734 FIRRTLType type;
5735 LocWithInfo info(getToken().getLoc(), this);
5736 if (parseId(name, "expected port name") ||
5737 parseToken(FIRToken::colon, "expected ':' in port definition") ||
5738 parseType(type, "expected a type in port declaration"))
5739 return failure();
5740 Attribute domainInfoElement = {};
5741 size_t portIdx = resultPorts.size();
5742 if (auto domainType = dyn_cast<DomainType>(type)) {
5743 // Domain information is now stored in the type itself.
5744 // Domain type ports have no associations.
5745 domainInfoElement = ArrayAttr::get(getContext(), {});
5746 } else {
5747 if (getToken().is(FIRToken::kw_domains))
5748 if (parseDomains(domainNames[portIdx], nameToIndex))
5749 return failure();
5750 }
5751
5752 if (info.parseOptionalInfo())
5753 return failure();
5754
5755 StringAttr innerSym = {};
5756 resultPorts.push_back(PortInfo{name,
5757 type,
5758 direction::get(isOutput),
5759 innerSym,
5760 info.getLoc(),
5761 {},
5762 domainInfoElement});
5763 resultPortLocs.push_back(info.getFIRLoc());
5764 nameToIndex.insert({name, portIdx});
5765 }
5766
5767 // Apply domain assocations to ports.
5768 for (size_t portIdx = 0, e = resultPorts.size(); portIdx != e; ++portIdx) {
5769 auto &port = resultPorts[portIdx];
5770 Attribute &attr = port.domains;
5771 if (attr)
5772 continue;
5773
5774 SmallVector<Attribute> domainInfo;
5775 if (failed(resolveDomains(domainNames[portIdx], nameToIndex, domainInfo)))
5776 return failure();
5777 attr = ArrayAttr::get(getContext(), domainInfo);
5778 }
5779
5780 // Check for port name collisions.
5782 for (auto portAndLoc : llvm::zip(resultPorts, resultPortLocs)) {
5783 PortInfo &port = std::get<0>(portAndLoc);
5784 auto &entry = portIds[port.name];
5785 if (!entry.isValid()) {
5786 entry = std::get<1>(portAndLoc);
5787 continue;
5788 }
5789
5790 emitError(std::get<1>(portAndLoc),
5791 "redefinition of name '" + port.getName() + "'")
5792 .attachNote(translateLocation(entry))
5793 << "previous definition here";
5794 return failure();
5795 }
5796
5797 return success();
5798}
5799
5800/// We're going to defer parsing this module, so just skip tokens until we
5801/// get to the next module or the end of the file.
5802ParseResult FIRCircuitParser::skipToModuleEnd(unsigned indent) {
5803 while (true) {
5804 switch (getToken().getKind()) {
5805
5806 // End of file or invalid token will be handled by outer level.
5807 case FIRToken::eof:
5808 case FIRToken::error:
5809 return success();
5810
5811 // If we got to the next top-level declaration, then we're done.
5812 case FIRToken::kw_class:
5813 case FIRToken::kw_domain:
5814 case FIRToken::kw_declgroup:
5815 case FIRToken::kw_extclass:
5816 case FIRToken::kw_extmodule:
5817 case FIRToken::kw_intmodule:
5818 case FIRToken::kw_formal:
5819 case FIRToken::kw_module:
5820 case FIRToken::kw_public:
5821 case FIRToken::kw_layer:
5822 case FIRToken::kw_option:
5823 case FIRToken::kw_simulation:
5824 case FIRToken::kw_type:
5825 // All module declarations should have the same indentation
5826 // level. Use this fact to differentiate between module
5827 // declarations and usages of "module" as identifiers.
5828 if (getIndentation() == indent)
5829 return success();
5830 [[fallthrough]];
5831 default:
5832 consumeToken();
5833 break;
5834 }
5835 }
5836}
5837
5838/// parameter-list ::= parameter*
5839/// parameter ::= 'parameter' param NEWLINE
5840ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5841 SmallVector<Attribute, 8> parameters;
5842 SmallPtrSet<StringAttr, 8> seen;
5843 while (consumeIf(FIRToken::kw_parameter)) {
5844 StringAttr name;
5845 Attribute value;
5846 SMLoc loc;
5847 if (parseParameter(name, value, loc))
5848 return failure();
5849 auto typedValue = dyn_cast<TypedAttr>(value);
5850 if (!typedValue)
5851 return emitError(loc)
5852 << "invalid value for parameter '" << name.getValue() << "'";
5853 if (!seen.insert(name).second)
5854 return emitError(loc,
5855 "redefinition of parameter '" + name.getValue() + "'");
5856 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5857 }
5858 resultParameters = ArrayAttr::get(getContext(), parameters);
5859 return success();
5860}
5861
5862/// class ::= 'class' id ':' info? INDENT portlist simple_stmt_block DEDENT
5863ParseResult FIRCircuitParser::parseClass(CircuitOp circuit, unsigned indent) {
5864 StringAttr name;
5865 SmallVector<PortInfo, 8> portList;
5866 SmallVector<SMLoc> portLocs;
5867 LocWithInfo info(getToken().getLoc(), this);
5868
5869 if (requireFeature(missingSpecFIRVersion, "classes"))
5870 return failure();
5871
5872 consumeToken(FIRToken::kw_class);
5873 if (parseId(name, "expected class name") ||
5874 parseToken(FIRToken::colon, "expected ':' in class definition") ||
5875 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
5876 return failure();
5877
5878 if (name == circuit.getName())
5879 return mlir::emitError(info.getLoc(),
5880 "class cannot be the top of a circuit");
5881
5882 for (auto &portInfo : portList)
5883 if (!isa<PropertyType>(portInfo.type))
5884 return mlir::emitError(portInfo.loc,
5885 "ports on classes must be properties");
5886
5887 // build it
5888 auto builder = circuit.getBodyBuilder();
5889 auto classOp = ClassOp::create(builder, info.getLoc(), name, portList);
5890 classOp.setPrivate();
5891 deferredModules.emplace_back(
5892 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5893
5894 // Stash the class name -> op in the constants, so we can resolve Inst types.
5895 getConstants().classMap[name.getValue()] = classOp;
5896 return skipToModuleEnd(indent);
5897}
5898
5899/// domain ::= 'domain' id ':' info?
5900ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit, unsigned indent) {
5901 consumeToken(FIRToken::kw_domain);
5902
5903 StringAttr name;
5904 LocWithInfo info(getToken().getLoc(), this);
5905 if (parseId(name, "domain name") ||
5906 parseToken(FIRToken::colon, "expected ':' after domain definition") ||
5907 info.parseOptionalInfo())
5908 return failure();
5909
5910 SmallVector<Attribute> fields;
5911 while (true) {
5912 auto nextIndent = getIndentation();
5913 if (!nextIndent || *nextIndent <= indent)
5914 break;
5915
5916 StringAttr fieldName;
5917 PropertyType type;
5918 if (parseId(fieldName, "field name") ||
5919 parseToken(FIRToken::colon, "expected ':' after field name") ||
5920 parsePropertyType(type, "field type") || info.parseOptionalInfo())
5921 return failure();
5922
5923 fields.push_back(
5924 DomainFieldAttr::get(circuit.getContext(), fieldName, type));
5925 }
5926
5927 auto builder = circuit.getBodyBuilder();
5928 auto domainOp = DomainOp::create(builder, info.getLoc(), name,
5929 builder.getArrayAttr(fields));
5930
5931 // Stash the domain name -> op in the constants, so we can resolve Domain
5932 // types.
5933 getConstants().domainMap[name.getValue()] = domainOp;
5934
5935 return success();
5936}
5937
5938/// extclass ::= 'extclass' id ':' info? INDENT portlist DEDENT
5939ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
5940 unsigned indent) {
5941 StringAttr name;
5942 SmallVector<PortInfo, 8> portList;
5943 SmallVector<SMLoc> portLocs;
5944 LocWithInfo info(getToken().getLoc(), this);
5945
5946 if (requireFeature(missingSpecFIRVersion, "classes"))
5947 return failure();
5948
5949 consumeToken(FIRToken::kw_extclass);
5950 if (parseId(name, "expected extclass name") ||
5951 parseToken(FIRToken::colon, "expected ':' in extclass definition") ||
5952 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
5953 return failure();
5954
5955 if (name == circuit.getName())
5956 return mlir::emitError(info.getLoc(),
5957 "extclass cannot be the top of a circuit");
5958
5959 for (auto &portInfo : portList)
5960 if (!isa<PropertyType>(portInfo.type))
5961 return mlir::emitError(portInfo.loc,
5962 "ports on extclasses must be properties");
5963
5964 // Build it
5965 auto builder = circuit.getBodyBuilder();
5966 auto extClassOp = ExtClassOp::create(builder, info.getLoc(), name, portList);
5967
5968 // Stash the class name -> op in the constants, so we can resolve Inst types.
5969 getConstants().classMap[name.getValue()] = extClassOp;
5970 return skipToModuleEnd(indent);
5971}
5972
5973/// extmodule ::=
5974/// 'extmodule' id requires? ':' info?
5975/// INDENT portlist defname? parameter-list DEDENT
5976/// defname ::= 'defname' '=' id NEWLINE
5977/// requires ::= 'requires' string (',' string)*
5978ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5979 unsigned indent) {
5980 StringAttr name;
5981 ArrayAttr enabledLayers;
5982 ArrayAttr knownLayers;
5983 ArrayAttr externalRequirements;
5984 SmallVector<PortInfo, 8> portList;
5985 SmallVector<SMLoc> portLocs;
5986 LocWithInfo info(getToken().getLoc(), this);
5987 consumeToken(FIRToken::kw_extmodule);
5988 if (parseId(name, "expected extmodule name") ||
5989 parseExtModuleAttributesSpec(enabledLayers, knownLayers,
5990 externalRequirements) ||
5991 parseToken(FIRToken::colon, "expected ':' in extmodule definition") ||
5992 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
5993 return failure();
5994
5995 StringRef defName;
5996 if (consumeIf(FIRToken::kw_defname)) {
5997 if (parseToken(FIRToken::equal, "expected '=' in defname") ||
5998 parseId(defName, "expected defname name"))
5999 return failure();
6000 }
6001
6002 ArrayAttr parameters;
6003 if (parseParameterList(parameters))
6004 return failure();
6005
6006 if (version >= FIRVersion({4, 0, 0})) {
6007 for (auto [pi, loc] : llvm::zip_equal(portList, portLocs)) {
6008 if (auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6009 if (ftype.hasUninferredWidth())
6010 return emitError(loc, "extmodule port must have known width");
6011 }
6012 }
6013 }
6014
6015 auto builder = circuit.getBodyBuilder();
6016 auto isMainModule = (name == circuit.getName());
6017 auto convention =
6018 (isMainModule && getConstants().options.scalarizePublicModules) ||
6019 getConstants().options.scalarizeExtModules
6020 ? Convention::Scalarized
6021 : Convention::Internal;
6022 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6023 auto annotations = ArrayAttr::get(getContext(), {});
6024 auto extModuleOp = FExtModuleOp::create(
6025 builder, info.getLoc(), name, conventionAttr, portList, knownLayers,
6026 defName, annotations, parameters, enabledLayers, externalRequirements);
6027 auto visibility = isMainModule ? SymbolTable::Visibility::Public
6028 : SymbolTable::Visibility::Private;
6029 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
6030 return success();
6031}
6032
6033/// intmodule ::=
6034/// 'intmodule' id ':' info?
6035/// INDENT portlist intname parameter-list ref-list DEDENT
6036/// intname ::= 'intrinsic' '=' id NEWLINE
6037ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
6038 unsigned indent) {
6039 StringAttr name;
6040 StringRef intName;
6041 ArrayAttr enabledLayers;
6042 SmallVector<PortInfo, 8> portList;
6043 SmallVector<SMLoc> portLocs;
6044 LocWithInfo info(getToken().getLoc(), this);
6045 consumeToken(FIRToken::kw_intmodule);
6046 if (parseId(name, "expected intmodule name") ||
6047 parseModuleLayerSpec(enabledLayers) ||
6048 parseToken(FIRToken::colon, "expected ':' in intmodule definition") ||
6049 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent) ||
6050 parseToken(FIRToken::kw_intrinsic, "expected 'intrinsic'") ||
6051 parseToken(FIRToken::equal, "expected '=' in intrinsic") ||
6052 parseId(intName, "expected intrinsic name"))
6053 return failure();
6054
6055 ArrayAttr parameters;
6056 if (parseParameterList(parameters))
6057 return failure();
6058
6059 ArrayAttr annotations = getConstants().emptyArrayAttr;
6060 auto builder = circuit.getBodyBuilder();
6061 FIntModuleOp::create(builder, info.getLoc(), name, portList, intName,
6062 annotations, parameters, enabledLayers)
6063 .setPrivate();
6064 return success();
6065}
6066
6067/// module ::= 'module' id ':' info? INDENT portlist simple_stmt_block DEDENT
6068ParseResult FIRCircuitParser::parseModule(CircuitOp circuit, bool isPublic,
6069 unsigned indent) {
6070 StringAttr name;
6071 SmallVector<PortInfo, 8> portList;
6072 SmallVector<SMLoc> portLocs;
6073 ArrayAttr enabledLayers;
6074 auto modLoc = getToken().getLoc();
6075 LocWithInfo info(modLoc, this);
6076 consumeToken(FIRToken::kw_module);
6077 if (parseId(name, "expected module name") ||
6078 parseModuleLayerSpec(enabledLayers) ||
6079 parseToken(FIRToken::colon, "expected ':' in module definition") ||
6080 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
6081 return failure();
6082
6083 // The main module is implicitly public.
6084 if (name == circuit.getName()) {
6085 if (!isPublic && removedFeature({4, 0, 0}, "private main modules", modLoc))
6086 return failure();
6087 isPublic = true;
6088 }
6089
6090 if (isPublic && version >= FIRVersion({4, 0, 0})) {
6091 for (auto [pi, loc] : llvm::zip_equal(portList, portLocs)) {
6092 if (auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6093 if (ftype.hasUninferredWidth())
6094 return emitError(loc, "public module port must have known width");
6095 if (ftype.hasUninferredReset())
6096 return emitError(loc,
6097 "public module port must have concrete reset type");
6098 }
6099 }
6100 }
6101
6102 ArrayAttr annotations = getConstants().emptyArrayAttr;
6103 auto convention = Convention::Internal;
6104 if (isPublic && getConstants().options.scalarizePublicModules)
6105 convention = Convention::Scalarized;
6106 if (!isPublic && getConstants().options.scalarizeInternalModules)
6107 convention = Convention::Scalarized;
6108 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6109 auto builder = circuit.getBodyBuilder();
6110 auto moduleOp =
6111 FModuleOp::create(builder, info.getLoc(), name, conventionAttr, portList,
6112 annotations, enabledLayers);
6113
6114 auto visibility = isPublic ? SymbolTable::Visibility::Public
6115 : SymbolTable::Visibility::Private;
6116 SymbolTable::setSymbolVisibility(moduleOp, visibility);
6117
6118 // Parse the body of this module after all prototypes have been parsed. This
6119 // allows us to handle forward references correctly.
6120 deferredModules.emplace_back(DeferredModuleToParse{
6121 moduleOp, portLocs, getLexer().getCursor(), indent});
6122
6123 if (skipToModuleEnd(indent))
6124 return failure();
6125 return success();
6126}
6127
6128/// formal ::= 'formal' formal-like
6129ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit, unsigned indent) {
6130 consumeToken(FIRToken::kw_formal);
6131 return parseFormalLike<FormalOp>(circuit, indent);
6132}
6133
6134/// simulation ::= 'simulation' formal-like
6135ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
6136 unsigned indent) {
6137 consumeToken(FIRToken::kw_simulation);
6138 return parseFormalLike<SimulationOp>(circuit, indent);
6139}
6140
6141/// formal-like ::= formal-like-old | formal-like-new
6142/// formal-like-old ::= id 'of' id ',' 'bound' '=' int info?
6143/// formal-like-new ::= id 'of' id ':' info? INDENT (param NEWLINE)* DEDENT
6144template <class Op>
6145ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
6146 unsigned indent) {
6147 StringRef id, moduleName;
6148 int64_t bound = 0;
6149 LocWithInfo info(getToken().getLoc(), this);
6150 auto builder = circuit.getBodyBuilder();
6151
6152 // Parse the name and target module of the test.
6153 if (parseId(id, "expected test name") ||
6154 parseToken(FIRToken::kw_of, "expected 'of' in test") ||
6155 parseId(moduleName, "expected module name"))
6156 return failure();
6157
6158 // TODO: Remove the old `, bound = N` variant in favor of the new parameters.
6159 NamedAttrList params;
6160 if (consumeIf(FIRToken::comma)) {
6161 // Parse the old style declaration with a `, bound = N` suffix.
6162 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() != "bound")
6163 return emitError("expected 'bound' after ','");
6164 consumeToken();
6165 if (parseToken(FIRToken::equal, "expected '=' after 'bound'") ||
6166 parseIntLit(bound, "expected integer bound after '='"))
6167 return failure();
6168 if (bound <= 0)
6169 return emitError("bound must be a positive integer");
6170 if (info.parseOptionalInfo())
6171 return failure();
6172 params.set("bound", builder.getIntegerAttr(builder.getI32Type(), bound));
6173 } else {
6174 // Parse the new style declaration with a `:` and parameter list.
6175 if (parseToken(FIRToken::colon, "expected ':' in test") ||
6176 info.parseOptionalInfo())
6177 return failure();
6178 while (getIndentation() > indent) {
6179 StringAttr paramName;
6180 Attribute paramValue;
6181 SMLoc paramLoc;
6182 if (parseParameter(paramName, paramValue, paramLoc,
6183 /*allowAggregates=*/true))
6184 return failure();
6185 if (params.set(paramName, paramValue))
6186 return emitError(paramLoc, "redefinition of parameter '" +
6187 paramName.getValue() + "'");
6188 }
6189 }
6190
6191 Op::create(builder, info.getLoc(), id, moduleName,
6192 params.getDictionary(getContext()));
6193 return success();
6194}
6195
6196ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
6197 unsigned indent) {
6198 switch (getToken().getKind()) {
6199 case FIRToken::kw_class:
6200 return parseClass(circuit, indent);
6201 case FIRToken::kw_declgroup:
6202 if (requireFeature({3, 2, 0}, "optional groups") ||
6203 removedFeature({3, 3, 0}, "optional groups"))
6204 return failure();
6205 return parseLayer(circuit);
6206 case FIRToken::kw_domain:
6207 if (requireFeature(missingSpecFIRVersion, "domains"))
6208 return failure();
6209 return parseDomain(circuit, indent);
6210 case FIRToken::kw_extclass:
6211 return parseExtClass(circuit, indent);
6212 case FIRToken::kw_extmodule:
6213 return parseExtModule(circuit, indent);
6214 case FIRToken::kw_formal:
6215 if (requireFeature({4, 0, 0}, "formal tests"))
6216 return failure();
6217 return parseFormal(circuit, indent);
6218 case FIRToken::kw_intmodule:
6219 if (requireFeature({1, 2, 0}, "intrinsic modules") ||
6220 removedFeature({4, 0, 0}, "intrinsic modules"))
6221 return failure();
6222 return parseIntModule(circuit, indent);
6223 case FIRToken::kw_layer:
6224 if (requireFeature({3, 3, 0}, "layers"))
6225 return failure();
6226 return parseLayer(circuit);
6227 case FIRToken::kw_module:
6228 return parseModule(circuit, /*isPublic=*/false, indent);
6229 case FIRToken::kw_public:
6230 if (requireFeature({3, 3, 0}, "public modules"))
6231 return failure();
6232 consumeToken();
6233 if (getToken().getKind() == FIRToken::kw_module)
6234 return parseModule(circuit, /*isPublic=*/true, indent);
6235 return emitError(getToken().getLoc(), "only modules may be public");
6236 case FIRToken::kw_simulation:
6237 if (requireFeature(nextFIRVersion, "simulation tests"))
6238 return failure();
6239 return parseSimulation(circuit, indent);
6240 case FIRToken::kw_type:
6241 return parseTypeDecl();
6242 case FIRToken::kw_option:
6243 if (requireFeature(missingSpecFIRVersion, "option groups/instance choices"))
6244 return failure();
6245 return parseOptionDecl(circuit);
6246 default:
6247 return emitError(getToken().getLoc(), "unknown toplevel definition");
6248 }
6249}
6250
6251// Parse a type declaration.
6252ParseResult FIRCircuitParser::parseTypeDecl() {
6253 StringRef id;
6254 FIRRTLType type;
6255 consumeToken();
6256 auto loc = getToken().getLoc();
6257
6258 if (getToken().isKeyword())
6259 return emitError(loc) << "cannot use keyword '" << getToken().getSpelling()
6260 << "' for type alias name";
6261
6262 if (parseId(id, "expected type name") ||
6263 parseToken(FIRToken::equal, "expected '=' in type decl") ||
6264 parseType(type, "expected a type"))
6265 return failure();
6266 auto name = StringAttr::get(type.getContext(), id);
6267 // Create type alias only for base types. Otherwise just pass through the
6268 // type.
6269 if (auto base = type_dyn_cast<FIRRTLBaseType>(type))
6270 type = BaseTypeAliasType::get(name, base);
6271 else
6272 emitWarning(loc)
6273 << "type alias for non-base type " << type
6274 << " is currently not supported. Type alias is stripped immediately";
6275
6276 if (!getConstants().aliasMap.insert({id, type}).second)
6277 return emitError(loc) << "type alias `" << name.getValue()
6278 << "` is already defined";
6279 return success();
6280}
6281
6282// Parse an option group declaration.
6283ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6284 StringRef id;
6285 consumeToken();
6286 auto loc = getToken().getLoc();
6287
6288 LocWithInfo info(getToken().getLoc(), this);
6289 if (parseId(id, "expected an option group name") ||
6290 parseToken(FIRToken::colon,
6291 "expected ':' after option group definition") ||
6292 info.parseOptionalInfo())
6293 return failure();
6294
6295 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6296 auto optionOp = OptionOp::create(builder, info.getLoc(), id);
6297 auto *block = new Block;
6298 optionOp.getBody().push_back(block);
6299 builder.setInsertionPointToEnd(block);
6300
6301 auto baseIndent = getIndentation();
6302 StringSet<> cases;
6303 while (getIndentation() == baseIndent) {
6304 StringRef id;
6305 LocWithInfo caseInfo(getToken().getLoc(), this);
6306 if (parseId(id, "expected an option case ID") ||
6307 caseInfo.parseOptionalInfo())
6308 return failure();
6309
6310 if (!cases.insert(id).second)
6311 return emitError(loc)
6312 << "duplicate option case definition '" << id << "'";
6313
6314 OptionCaseOp::create(builder, caseInfo.getLoc(), id);
6315 }
6316
6317 return success();
6318}
6319
6320// Parse a layer definition.
6321ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6322 auto baseIndent = getIndentation();
6323
6324 // A stack of all layers that are possibly parents of the current layer.
6325 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6326
6327 // Parse a single layer and add it to the layerStack.
6328 auto parseOne = [&](Block *block) -> ParseResult {
6329 auto indent = getIndentation();
6330 StringRef id, convention;
6331 LocWithInfo info(getToken().getLoc(), this);
6332 consumeToken();
6333 if (parseId(id, "expected layer name") ||
6334 parseToken(FIRToken::comma, "expected ','") ||
6335 parseGetSpelling(convention))
6336 return failure();
6337
6338 auto layerConvention = symbolizeLayerConvention(convention);
6339 if (!layerConvention) {
6340 emitError() << "unknown convention '" << convention
6341 << "' (did you misspell it?)";
6342 return failure();
6343 }
6344 if (layerConvention == LayerConvention::Inline &&
6345 requireFeature({4, 1, 0}, "inline layers"))
6346 return failure();
6347 consumeToken();
6348
6349 hw::OutputFileAttr outputDir;
6350 if (consumeIf(FIRToken::comma)) {
6351 if (getToken().getKind() == FIRToken::string) {
6352 auto text = getToken().getStringValue();
6353 if (text.empty())
6354 return emitError() << "output directory must not be blank";
6355 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6356 consumeToken(FIRToken::string);
6357 }
6358 }
6359
6360 if (parseToken(FIRToken::colon, "expected ':' after layer definition") ||
6361 info.parseOptionalInfo())
6362 return failure();
6363 auto builder = OpBuilder::atBlockEnd(block);
6364 // Create the layer definition and give it an empty block.
6365 auto layerOp =
6366 LayerOp::create(builder, info.getLoc(), id, *layerConvention);
6367 layerOp->getRegion(0).push_back(new Block());
6368 if (outputDir)
6369 layerOp->setAttr("output_file", outputDir);
6370 layerStack.push_back({indent, layerOp});
6371 return success();
6372 };
6373
6374 if (parseOne(circuit.getBodyBlock()))
6375 return failure();
6376
6377 // Parse any nested layers.
6378 while (getIndentation() > baseIndent) {
6379 switch (getToken().getKind()) {
6380 case FIRToken::kw_declgroup:
6381 case FIRToken::kw_layer: {
6382 // Pop nested layers off the stack until we find out what layer to insert
6383 // this into.
6384 while (layerStack.back().first >= getIndentation())
6385 layerStack.pop_back();
6386 auto parentLayer = layerStack.back().second;
6387 if (parseOne(&parentLayer.getBody().front()))
6388 return failure();
6389 break;
6390 }
6391 default:
6392 return emitError("expected 'layer'"), failure();
6393 }
6394 }
6395
6396 return success();
6397}
6398
6399ParseResult FIRCircuitParser::resolveDomains(
6400 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
6401 const DenseMap<Attribute, size_t> &nameToIndex,
6402 SmallVectorImpl<Attribute> &domainsByIndex) {
6403
6404 for (auto [attr, loc] : domainsByName) {
6405 auto domain = cast<StringAttr>(attr);
6406 auto indexItr = nameToIndex.find(domain);
6407 if (indexItr == nameToIndex.end()) {
6408 emitError(loc) << "unknown domain name '" << domain.getValue() << "'";
6409 return failure();
6410 }
6411 domainsByIndex.push_back(IntegerAttr::get(
6412 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6413 indexItr->second));
6414 }
6415
6416 return success();
6417}
6418
6419ParseResult FIRCircuitParser::parseDomains(
6420 SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
6421 const DenseMap<Attribute, size_t> &nameToIndex) {
6422 if (requireFeature(missingSpecFIRVersion, "domains"))
6423 return failure();
6424 if (parseToken(FIRToken::kw_domains, "expected 'domains'") ||
6425 parseToken(FIRToken::l_square, "expected '['"))
6426 return failure();
6427
6428 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6429 StringAttr domain;
6430 auto domainLoc = getToken().getLoc();
6431 if (parseId(domain, "expected domain name"))
6432 return failure();
6433 domains.push_back({domain, domainLoc});
6434 return success();
6435 }))
6436 return failure();
6437
6438 return success();
6439}
6440
6441// Parse the body of this module.
6442ParseResult
6443FIRCircuitParser::parseModuleBody(const SymbolTable &circuitSymTbl,
6444 DeferredModuleToParse &deferredModule,
6445 InnerSymFixups &fixups) {
6446 FModuleLike moduleOp = deferredModule.moduleOp;
6447 auto &body = moduleOp->getRegion(0).front();
6448 auto &portLocs = deferredModule.portLocs;
6449
6450 // We parse the body of this module with its own lexer, enabling parallel
6451 // parsing with the rest of the other module bodies.
6452 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6453
6454 // Reset the parser/lexer state back to right after the port list.
6455 deferredModule.lexerCursor.restore(moduleBodyLexer);
6456
6457 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6458 version);
6459
6460 // Install all of the ports into the symbol table, associated with their
6461 // block arguments.
6462 auto portList = moduleOp.getPorts();
6463 auto portArgs = body.getArguments();
6464 for (auto tuple : llvm::zip(portList, portLocs, portArgs)) {
6465 PortInfo &port = std::get<0>(tuple);
6466 llvm::SMLoc loc = std::get<1>(tuple);
6467 BlockArgument portArg = std::get<2>(tuple);
6468 assert(!port.sym);
6469 if (moduleContext.addSymbolEntry(port.getName(), portArg, loc))
6470 return failure();
6471 }
6472
6473 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6474
6475 // Parse the moduleBlock.
6476 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6477 if (failed(result))
6478 return result;
6479
6480 // Scan for printf-encoded verif's to error on their use, no longer supported.
6481 {
6482 size_t numVerifPrintfs = 0;
6483 std::optional<Location> printfLoc;
6484
6485 deferredModule.moduleOp.walk([&](PrintFOp printFOp) {
6487 return;
6488 ++numVerifPrintfs;
6489 if (!printfLoc)
6490 printfLoc = printFOp.getLoc();
6491 });
6492
6493 if (numVerifPrintfs > 0) {
6494 auto diag =
6495 mlir::emitError(deferredModule.moduleOp.getLoc(), "module contains ")
6496 << numVerifPrintfs
6497 << " printf-encoded verification operation(s), which are no longer "
6498 "supported.";
6499 diag.attachNote(*printfLoc)
6500 << "example printf here, this is now just a printf and nothing more";
6501 diag.attachNote() << "For more information, see "
6502 "https://github.com/llvm/circt/issues/6970";
6503 return diag;
6504 }
6505 }
6506
6507 return success();
6508}
6509
6510/// file ::= circuit
6511/// versionHeader ::= 'FIRRTL' 'version' versionLit NEWLINE
6512/// circuit ::= versionHeader? 'circuit' id ':' info? INDENT module* DEDENT EOF
6513///
6514/// If non-null, annotationsBuf is a memory buffer containing JSON annotations.
6515///
6516ParseResult FIRCircuitParser::parseCircuit(
6517 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6518 mlir::TimingScope &ts) {
6519
6520 auto indent = getIndentation();
6521 if (parseToken(FIRToken::kw_FIRRTL, "expected 'FIRRTL'"))
6522 return failure();
6523 if (!indent.has_value())
6524 return emitError("'FIRRTL' must be first token on its line");
6525 if (parseToken(FIRToken::kw_version, "expected version after 'FIRRTL'") ||
6526 parseVersionLit("expected version literal"))
6527 return failure();
6528 indent = getIndentation();
6529
6530 if (!indent.has_value())
6531 return emitError("'circuit' must be first token on its line");
6532 unsigned circuitIndent = *indent;
6533
6534 LocWithInfo info(getToken().getLoc(), this);
6535 StringAttr name;
6536 SMLoc inlineAnnotationsLoc;
6537 StringRef inlineAnnotations;
6538
6539 // A file must contain a top level `circuit` definition.
6540 if (parseToken(FIRToken::kw_circuit,
6541 "expected a top-level 'circuit' definition") ||
6542 parseId(name, "expected circuit name") ||
6543 parseToken(FIRToken::colon, "expected ':' in circuit definition") ||
6544 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6545 info.parseOptionalInfo())
6546 return failure();
6547
6548 // Create the top-level circuit op in the MLIR module.
6549 OpBuilder b(mlirModule.getBodyRegion());
6550 auto circuit = CircuitOp::create(b, info.getLoc(), name);
6551
6552 // A timer to get execution time of annotation parsing.
6553 auto parseAnnotationTimer = ts.nest("Parse annotations");
6554
6555 // Deal with any inline annotations, if they exist. These are processed
6556 // first to place any annotations from an annotation file *after* the inline
6557 // annotations. While arbitrary, this makes the annotation file have
6558 // "append" semantics.
6559 SmallVector<Attribute> annos;
6560 if (!inlineAnnotations.empty())
6561 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6562 return failure();
6563
6564 // Deal with the annotation file if one was specified
6565 for (auto *annotationsBuf : annotationsBufs)
6566 if (importAnnotationsRaw(info.getFIRLoc(), annotationsBuf->getBuffer(),
6567 annos))
6568 return failure();
6569
6570 parseAnnotationTimer.stop();
6571
6572 // Get annotations that are supposed to be specially handled by the
6573 // LowerAnnotations pass.
6574 if (!annos.empty())
6575 circuit->setAttr(rawAnnotations, b.getArrayAttr(annos));
6576
6577 // A timer to get execution time of module parsing.
6578 auto parseTimer = ts.nest("Parse modules");
6579 deferredModules.reserve(16);
6580
6581 // Parse any contained modules.
6582 while (true) {
6583 switch (getToken().getKind()) {
6584 // If we got to the end of the file, then we're done.
6585 case FIRToken::eof:
6586 goto DoneParsing;
6587
6588 // If we got an error token, then the lexer already emitted an error,
6589 // just stop. We could introduce error recovery if there was demand for
6590 // it.
6591 case FIRToken::error:
6592 return failure();
6593
6594 default:
6595 emitError("unexpected token in circuit");
6596 return failure();
6597
6598 case FIRToken::kw_class:
6599 case FIRToken::kw_declgroup:
6600 case FIRToken::kw_domain:
6601 case FIRToken::kw_extclass:
6602 case FIRToken::kw_extmodule:
6603 case FIRToken::kw_intmodule:
6604 case FIRToken::kw_layer:
6605 case FIRToken::kw_formal:
6606 case FIRToken::kw_module:
6607 case FIRToken::kw_option:
6608 case FIRToken::kw_public:
6609 case FIRToken::kw_simulation:
6610 case FIRToken::kw_type: {
6611 auto indent = getIndentation();
6612 if (!indent.has_value())
6613 return emitError("'module' must be first token on its line"), failure();
6614 unsigned definitionIndent = *indent;
6615
6616 if (definitionIndent <= circuitIndent)
6617 return emitError("module should be indented more"), failure();
6618
6619 if (parseToplevelDefinition(circuit, definitionIndent))
6620 return failure();
6621 break;
6622 }
6623 }
6624 }
6625
6626 // After the outline of the file has been parsed, we can go ahead and parse
6627 // all the bodies. This allows us to resolve forward-referenced modules and
6628 // makes it possible to parse their bodies in parallel.
6629DoneParsing:
6630 // Each of the modules may translate source locations, and doing so touches
6631 // the SourceMgr to build a line number cache. This isn't thread safe, so we
6632 // proactively touch it to make sure that it is always already created.
6633 (void)getLexer().translateLocation(info.getFIRLoc());
6634
6635 // Pre-verify symbol table, so we can construct it next. Ideally, we would do
6636 // this verification through the trait.
6637 { // Memory is tight in parsing.
6638 // Check that all symbols are uniquely named within child regions.
6639 DenseMap<Attribute, Location> nameToOrigLoc;
6640 for (auto &op : *circuit.getBodyBlock()) {
6641 // Check for a symbol name attribute.
6642 auto nameAttr =
6643 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
6644 if (!nameAttr)
6645 continue;
6646
6647 // Try to insert this symbol into the table.
6648 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6649 if (!it.second) {
6650 op.emitError()
6651 .append("redefinition of symbol named '", nameAttr.getValue(), "'")
6652 .attachNote(it.first->second)
6653 .append("see existing symbol definition here");
6654 return failure();
6655 }
6656 }
6657 }
6658
6659 SymbolTable circuitSymTbl(circuit);
6660
6661 moduleFixups.resize(deferredModules.size());
6662
6663 // Stub out inner symbol namespace for each module,
6664 // none should be added so do this now to avoid walking later
6665 // to discover that this is the case.
6666 for (auto &d : deferredModules)
6667 innerSymbolNamespaces.get(d.moduleOp.getOperation());
6668
6669 // Next, parse all the module bodies.
6670 auto anyFailed = mlir::failableParallelForEachN(
6671 getContext(), 0, deferredModules.size(), [&](size_t index) {
6672 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6673 moduleFixups[index]))
6674 return failure();
6675 return success();
6676 });
6677 if (failed(anyFailed))
6678 return failure();
6679
6680 // Walk operations created that have inner symbol references
6681 // that need replacing now that it's safe to create inner symbols everywhere.
6682 for (auto &fixups : moduleFixups) {
6683 if (failed(fixups.resolve(innerSymbolNamespaces)))
6684 return failure();
6685 }
6686
6687 // Helper to transform a layer name specification of the form `A::B::C` into
6688 // a SymbolRefAttr.
6689 auto parseLayerName = [&](StringRef name) -> Attribute {
6690 // Parse the layer name into a SymbolRefAttr.
6691 auto [head, rest] = name.split(".");
6692 SmallVector<FlatSymbolRefAttr> nestedRefs;
6693 while (!rest.empty()) {
6694 StringRef next;
6695 std::tie(next, rest) = rest.split(".");
6696 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6697 }
6698 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6699 };
6700
6701 auto getArrayAttr = [&](ArrayRef<std::string> strArray, auto getAttr) {
6702 SmallVector<Attribute> attrArray;
6703 auto *context = getContext();
6704 for (const auto &str : strArray)
6705 attrArray.push_back(getAttr(str));
6706 if (attrArray.empty())
6707 return ArrayAttr();
6708 return ArrayAttr::get(context, attrArray);
6709 };
6710
6711 if (auto enableLayers =
6712 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6713 circuit.setEnableLayersAttr(enableLayers);
6714 if (auto disableLayers =
6715 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6716 circuit.setDisableLayersAttr(disableLayers);
6717
6718 auto getStrAttr = [&](StringRef str) -> Attribute {
6719 return StringAttr::get(getContext(), str);
6720 };
6721
6722 if (auto selectInstChoice =
6723 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6724 circuit.setSelectInstChoiceAttr(selectInstChoice);
6725
6726 circuit.setDefaultLayerSpecialization(
6727 getConstants().options.defaultLayerSpecialization);
6728
6729 return success();
6730}
6731
6732//===----------------------------------------------------------------------===//
6733// Driver
6734//===----------------------------------------------------------------------===//
6735
6736// Parse the specified .fir file into the specified MLIR context.
6738circt::firrtl::importFIRFile(SourceMgr &sourceMgr, MLIRContext *context,
6739 mlir::TimingScope &ts, FIRParserOptions options) {
6740 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6741 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6742 unsigned fileID = 1;
6743 for (unsigned e = options.numAnnotationFiles + 1; fileID < e; ++fileID)
6744 annotationsBufs.push_back(
6745 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6746
6747 context->loadDialect<CHIRRTLDialect>();
6748 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6749
6750 // This is the result module we are parsing into.
6751 mlir::OwningOpRef<mlir::ModuleOp> module(ModuleOp::create(
6752 FileLineColLoc::get(context, sourceBuf->getBufferIdentifier(),
6753 /*line=*/0,
6754 /*column=*/0)));
6755 SharedParserConstants state(context, options);
6756 FIRLexer lexer(sourceMgr, context);
6757 if (FIRCircuitParser(state, lexer, *module, minimumFIRVersion)
6758 .parseCircuit(annotationsBufs, ts))
6759 return nullptr;
6760
6761 // Make sure the parse module has no other structural problems detected by
6762 // the verifier.
6763 auto circuitVerificationTimer = ts.nest("Verify circuit");
6764 if (failed(verify(*module)))
6765 return {};
6766
6767 return module;
6768}
6769
6771 static mlir::TranslateToMLIRRegistration fromFIR(
6772 "import-firrtl", "import .fir",
6773 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
6774 mlir::TimingScope ts;
6775 return importFIRFile(sourceMgr, context, ts);
6776 });
6777}
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.