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