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