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