21#include "mlir/IR/BuiltinOps.h"
22#include "mlir/Tools/mlir-translate/Translation.h"
23#include "llvm/ADT/APSInt.h"
24#include "llvm/ADT/StringSet.h"
25#include "llvm/ADT/TypeSwitch.h"
26#include "llvm/Support/Debug.h"
28#define DEBUG_TYPE "export-firrtl"
31using namespace firrtl;
32using namespace chirrtl;
33using namespace pretty;
42constexpr size_t defaultTargetLineLength = 80;
46 Emitter(llvm::raw_ostream &os,
FIRVersion version,
47 size_t targetLineLength = defaultTargetLineLength)
48 : pp(os, targetLineLength), ps(pp, saver), version(version) {
49 pp.setListener(&saver);
51 LogicalResult finalize();
54 void emitCircuit(CircuitOp op);
55 void emitModule(FModuleOp op);
56 void emitModule(FExtModuleOp op);
57 void emitModule(FIntModuleOp op);
58 void emitModulePorts(ArrayRef<PortInfo> ports,
59 Block::BlockArgListType arguments = {});
60 void emitModuleParameters(Operation *op, ArrayAttr parameters);
61 void emitDeclaration(DomainOp op);
62 void emitDeclaration(LayerOp op);
63 void emitDeclaration(OptionOp op);
64 void emitDeclaration(FormalOp op);
65 void emitDeclaration(SimulationOp op);
66 void emitFormalLike(Operation *op, StringRef keyword, StringAttr symName,
67 StringAttr moduleName, DictionaryAttr params);
68 void emitEnabledLayers(ArrayRef<Attribute> layers);
69 void emitKnownLayers(ArrayRef<Attribute> layers);
70 void emitParamAssign(ParamDeclAttr param, Operation *op,
71 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
72 void emitParamValue(Attribute value, Operation *op);
74 void emitGenericIntrinsic(GenericIntrinsicOp op);
77 void emitStatementsInBlock(
Block &block);
78 void emitStatement(WhenOp op);
79 void emitStatement(WireOp op);
80 void emitStatement(RegOp op);
81 void emitStatement(RegResetOp op);
82 void emitStatement(NodeOp op);
83 void emitStatement(StopOp op);
84 void emitStatement(SkipOp op);
85 void emitFormatString(Operation *op, StringRef formatString, OperandRange ops,
86 llvm::SmallVectorImpl<Value> &substitutions);
88 void emitPrintfLike(T op, StringAttr fileName);
89 void emitStatement(PrintFOp op);
90 void emitStatement(FPrintFOp op);
91 void emitStatement(FFlushOp op);
92 void emitStatement(ConnectOp op);
93 void emitStatement(MatchingConnectOp op);
94 void emitStatement(PropAssignOp op);
95 void emitStatement(InstanceOp op);
96 void emitStatement(InstanceChoiceOp op);
97 void emitStatement(AttachOp op);
98 void emitStatement(MemOp op);
99 void emitStatement(InvalidValueOp op);
100 void emitStatement(CombMemOp op);
101 void emitStatement(SeqMemOp op);
102 void emitStatement(MemoryPortOp op);
103 void emitStatement(MemoryDebugPortOp op);
104 void emitStatement(MemoryPortAccessOp op);
105 void emitStatement(DomainDefineOp op);
106 void emitStatement(RefDefineOp op);
107 void emitStatement(RefForceOp op);
108 void emitStatement(RefForceInitialOp op);
109 void emitStatement(RefReleaseOp op);
110 void emitStatement(RefReleaseInitialOp op);
111 void emitStatement(LayerBlockOp op);
112 void emitStatement(GenericIntrinsicOp op);
113 void emitStatement(DomainCreateAnonOp op);
116 void emitVerifStatement(T op, StringRef mnemonic);
117 void emitStatement(AssertOp op) { emitVerifStatement(op,
"assert"); }
118 void emitStatement(AssumeOp op) { emitVerifStatement(op,
"assume"); }
119 void emitStatement(CoverOp op) { emitVerifStatement(op,
"cover"); }
122 void emitExpression(Value value);
123 void emitExpression(ConstantOp op);
124 void emitExpression(SpecialConstantOp op);
125 void emitExpression(SubfieldOp op);
126 void emitExpression(SubindexOp op);
127 void emitExpression(SubaccessOp op);
128 void emitExpression(OpenSubfieldOp op);
129 void emitExpression(OpenSubindexOp op);
130 void emitExpression(RefResolveOp op);
131 void emitExpression(RefSendOp op);
132 void emitExpression(RefSubOp op);
133 void emitExpression(RWProbeOp op);
134 void emitExpression(RefCastOp op);
135 void emitExpression(UninferredResetCastOp op);
136 void emitExpression(ConstCastOp op);
137 void emitExpression(StringConstantOp op);
138 void emitExpression(FIntegerConstantOp op);
139 void emitExpression(BoolConstantOp op);
140 void emitExpression(DoubleConstantOp op);
141 void emitExpression(ListCreateOp op);
142 void emitExpression(UnresolvedPathOp op);
143 void emitExpression(GenericIntrinsicOp op);
144 void emitExpression(CatPrimOp op);
145 void emitExpression(UnsafeDomainCastOp op);
147 void emitPrimExpr(StringRef mnemonic, Operation *op,
148 ArrayRef<uint32_t> attrs = {});
150 void emitExpression(BitsPrimOp op) {
151 emitPrimExpr(
"bits", op, {op.getHi(), op.getLo()});
153 void emitExpression(HeadPrimOp op) {
154 emitPrimExpr(
"head", op, op.getAmount());
156 void emitExpression(TailPrimOp op) {
157 emitPrimExpr(
"tail", op, op.getAmount());
159 void emitExpression(PadPrimOp op) { emitPrimExpr(
"pad", op, op.getAmount()); }
160 void emitExpression(ShlPrimOp op) { emitPrimExpr(
"shl", op, op.getAmount()); }
161 void emitExpression(ShrPrimOp op) { emitPrimExpr(
"shr", op, op.getAmount()); }
163 void emitExpression(TimeOp op){};
166#define HANDLE(OPTYPE, MNEMONIC) \
167 void emitExpression(OPTYPE op) { emitPrimExpr(MNEMONIC, op); }
182 HANDLE(DShlPrimOp,
"dshl");
183 HANDLE(DShlwPrimOp,
"dshlw");
184 HANDLE(DShrPrimOp,
"dshr");
186 HANDLE(AsSIntPrimOp,
"asSInt");
187 HANDLE(AsUIntPrimOp,
"asUInt");
188 HANDLE(AsAsyncResetPrimOp,
"asAsyncReset");
189 HANDLE(AsClockPrimOp,
"asClock");
193 HANDLE(AndRPrimOp,
"andr");
195 HANDLE(XorRPrimOp,
"xorr");
199 void emitAttribute(MemDirAttr attr);
200 void emitAttribute(RUWBehaviorAttr attr);
203 void emitType(Type type,
bool includeConst =
true);
204 void emitTypeWithColon(Type type) {
205 ps << PP::space <<
":" << PP::nbsp;
210 void emitDomains(Attribute attr, ArrayRef<PortInfo> ports);
213 void emitLocation(Location loc);
214 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
215 template <
typename... Args>
216 void emitLocationAndNewLine(Args... args) {
219 ps << PP::neverbreak;
220 emitLocation(args...);
224 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
225 llvm::function_ref<
void()> emitRHS,
227 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
229 ps.scopedBox(PP::ibox2, [&]() {
231 ps << *wordBeforeLHS << PP::space;
235 ps << PP::space << syntax << PP::nbsp;
237 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
242 void emitSubExprIBox2(Value v) {
243 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
248 template <
typename Container,
typename EachFn>
249 void interleaveComma(
const Container &c, EachFn eachFn) {
250 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
255 void interleaveComma(ValueRange ops) {
256 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
259 void emitStatementFunctionOp(
PPExtString name, Operation *op) {
262 ps.scopedBox(PP::ibox0, [&]() {
263 interleaveComma(op->getOperands());
266 emitLocationAndNewLine(op);
269 template <
typename EachFn,
typename Range>
270 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
273 ps.scopedBox(PP::ibox0, [&]() {
274 interleaveComma(r, eachFn);
279 void emitLiteralExpression(Type type, ValueRange values) {
280 return emitLiteralExpression(type, values,
281 [&](Value v) { emitSubExprIBox2(v); });
285 void emitSymbol(SymbolRefAttr symbol) {
286 ps.ibox(2, IndentStyle::Block);
287 ps << symbol.getRootReference();
288 for (
auto nested : symbol.getNestedReferences()) {
291 ps << nested.getAttr();
298 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
299 encounteredError =
true;
300 return op->emitError(message);
304 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
305 encounteredError =
true;
306 return op->emitOpError(message);
311 std::optional<StringRef> lookupEmittedName(Value value) {
312 auto it = valueNames.find(value);
313 if (it != valueNames.end())
320 void emitPendingNewlineIfNeeded() {
321 if (pendingNewline) {
322 pendingNewline =
false;
326 void setPendingNewline() {
328 pendingNewline =
true;
331 void startStatement() { emitPendingNewlineIfNeeded(); }
349 bool pendingNewline =
false;
352 bool encounteredError =
false;
357 DenseMap<Value, StringRef> valueNames;
358 StringSet<> valueNamesStorage;
362 StringAttr legalize(StringAttr attr) {
363 StringRef str = attr.getValue();
364 if (str.empty() || !
isdigit(str.front()))
366 return StringAttr::get(attr.getContext(),
"`" + Twine(attr) +
"`");
369 void addValueName(Value value, StringAttr attr) {
370 valueNames.insert({value, attr.getValue()});
372 void addValueName(Value value, StringRef str) {
373 auto it = valueNamesStorage.insert(str);
374 valueNames.insert({value, it.first->getKey()});
376 void addForceable(Forceable op, StringAttr attr) {
377 addValueName(op.getData(), attr);
378 if (op.isForceable()) {
379 SmallString<32> rwName;
380 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
381 addValueName(op.getDataRef(), rwName);
390 SymbolTable symbolTable;
393 SymInfos(Operation *op) : symbolTable(op), istc(op){};
395 std::optional<std::reference_wrapper<SymInfos>> symInfos;
402LogicalResult Emitter::finalize() {
return failure(encounteredError); }
405void Emitter::emitCircuit(CircuitOp op) {
406 circuitNamespace.add(op);
407 SymInfos circuitSymInfos(op);
408 symInfos = circuitSymInfos;
410 ps <<
"FIRRTL version ";
417 ps <<
"circuit " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
421 if (encounteredError)
423 TypeSwitch<Operation *>(&bodyOp)
424 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](
auto op) {
428 .Case<DomainOp, LayerOp, OptionOp, FormalOp, SimulationOp>(
429 [&](
auto op) { emitDeclaration(op); })
430 .Default([&](
auto op) {
431 emitOpError(op,
"not supported for emission inside circuit");
435 circuitNamespace.clear();
436 symInfos = std::nullopt;
439void Emitter::emitEnabledLayers(ArrayRef<Attribute> layers) {
440 for (
auto layer : layers) {
442 ps.
cbox(2, IndentStyle::Block);
443 ps <<
"enablelayer" << PP::space;
444 emitSymbol(cast<SymbolRefAttr>(layer));
449void Emitter::emitKnownLayers(ArrayRef<Attribute> layers) {
450 for (
auto layer : layers) {
452 ps.
cbox(2, IndentStyle::Block);
453 ps <<
"knownlayer" << PP::space;
454 emitSymbol(cast<SymbolRefAttr>(layer));
459void Emitter::emitParamAssign(ParamDeclAttr param, Operation *op,
460 std::optional<PPExtString> wordBeforeLHS) {
462 ps << *wordBeforeLHS << PP::nbsp;
464 ps <<
PPExtString(param.getName().strref()) << PP::nbsp <<
"=" << PP::nbsp;
465 emitParamValue(param.getValue(), op);
468void Emitter::emitParamValue(Attribute value, Operation *op) {
469 TypeSwitch<Attribute>(value)
470 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
471 .Case<FloatAttr>([&](
auto attr) {
473 attr.getValue().toString(str);
478 .Case<ArrayAttr>([&](
auto attr) {
481 interleaveComma(attr.getValue(),
482 [&](
auto element) { emitParamValue(element, op); });
486 .Case<DictionaryAttr>([&](
auto attr) {
489 interleaveComma(attr.getValue(), [&](
auto field) {
490 ps << PPExtString(field.getName()) << PP::nbsp <<
"=" << PP::nbsp;
491 emitParamValue(field.getValue(), op);
496 .Default([&](
auto attr) {
497 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
498 ps <<
"<unsupported-attr ";
504void Emitter::emitGenericIntrinsic(GenericIntrinsicOp op) {
508 ps << op.getIntrinsic();
510 auto params = op.getParameters();
511 if (!params.empty()) {
513 ps.scopedBox(PP::ibox0, [&]() {
515 params.getAsRange<ParamDeclAttr>(),
516 [&](ParamDeclAttr param) { emitParamAssign(param, op); });
521 if (op.getNumResults() != 0)
522 emitTypeWithColon(op.getResult().getType());
524 if (op.getNumOperands() != 0) {
525 ps <<
"," << PP::space;
526 ps.
scopedBox(PP::ibox0, [&]() { interleaveComma(op->getOperands()); });
533void Emitter::emitModule(FModuleOp op) {
535 ps.
cbox(4, IndentStyle::Block);
537 ps <<
"public" << PP::nbsp;
538 ps <<
"module " <<
PPExtString(legalize(op.getNameAttr()));
539 emitEnabledLayers(op.getLayers());
540 ps << PP::nbsp <<
":" << PP::end;
547 auto ports = op.getPorts();
548 emitModulePorts(ports, op.getArguments());
549 if (!ports.empty() && !op.getBodyBlock()->empty())
553 emitStatementsInBlock(*op.getBodyBlock());
556 valueNamesStorage.clear();
560void Emitter::emitModule(FExtModuleOp op) {
562 ps.
cbox(4, IndentStyle::Block);
563 ps <<
"extmodule " <<
PPExtString(legalize(op.getNameAttr()));
564 emitKnownLayers(op.getKnownLayers());
565 emitEnabledLayers(op.getLayers());
566 ps << PP::nbsp <<
":" << PP::end;
573 auto ports = op.getPorts();
574 emitModulePorts(ports);
577 if (op.getDefname() && !op.getDefname()->empty()) {
579 ps <<
"defname = " <<
PPExtString(*op.getDefname());
584 emitModuleParameters(op, op.getParameters());
589void Emitter::emitModule(FIntModuleOp op) {
591 ps.
cbox(4, IndentStyle::Block);
592 ps <<
"intmodule " <<
PPExtString(legalize(op.getNameAttr()));
593 emitEnabledLayers(op.getLayers());
594 ps << PP::nbsp <<
":" << PP::end;
601 auto ports = op.getPorts();
602 emitModulePorts(ports);
605 ps <<
"intrinsic = " <<
PPExtString(op.getIntrinsic());
609 emitModuleParameters(op, op.getParameters());
616void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
617 Block::BlockArgListType arguments) {
619 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
621 const auto &port = ports[i];
622 ps << (port.direction == Direction::In ?
"input " :
"output ");
623 auto legalName = legalize(port.name);
624 if (!arguments.empty())
625 addValueName(arguments[i], legalName);
628 emitDomains(port.domains, ports);
629 emitLocation(ports[i].loc);
634void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
635 for (
auto param : parameters.getAsRange<ParamDeclAttr>()) {
637 emitParamAssign(param, op,
PPExtString(
"parameter"));
642void Emitter::emitDeclaration(DomainOp op) {
644 ps <<
"domain " <<
PPExtString(op.getSymName()) <<
" :";
645 emitLocationAndNewLine(op);
647 for (
auto attr : op.getFields()) {
648 auto fieldAttr = cast<DomainFieldAttr>(attr);
649 ps << PP::newline <<
PPExtString(fieldAttr.getName()) <<
" : ";
650 emitType(fieldAttr.getType());
656void Emitter::emitDeclaration(LayerOp op) {
658 ps <<
"layer " <<
PPExtString(op.getSymName()) <<
", "
659 <<
PPExtString(stringifyLayerConvention(op.getConvention()));
661 if (
auto outputFile = op->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
667 emitLocationAndNewLine(op);
669 for (
auto &bodyOp : op.getBody().getOps()) {
670 TypeSwitch<Operation *>(&bodyOp)
671 .Case<LayerOp>([&](
auto op) { emitDeclaration(op); })
672 .Default([&](
auto op) {
674 "not supported for emission inside layer definition");
681void Emitter::emitDeclaration(OptionOp op) {
683 ps <<
"option " <<
PPExtString(legalize(op.getSymNameAttr())) <<
" :";
686 for (
auto caseOp : op.getBody().getOps<OptionCaseOp>()) {
688 ps <<
PPExtString(legalize(caseOp.getSymNameAttr()));
689 emitLocation(caseOp);
692 ps << PP::newline << PP::newline;
696void Emitter::emitDeclaration(FormalOp op) {
697 emitFormalLike(op,
"formal", op.getSymNameAttr(),
698 op.getModuleNameAttr().getAttr(), op.getParameters());
702void Emitter::emitDeclaration(SimulationOp op) {
703 emitFormalLike(op,
"simulation", op.getSymNameAttr(),
704 op.getModuleNameAttr().getAttr(), op.getParameters());
708void Emitter::emitFormalLike(Operation *op, StringRef keyword,
709 StringAttr symName, StringAttr moduleName,
710 DictionaryAttr params) {
712 ps.
cbox(4, IndentStyle::Block);
713 ps << keyword <<
" " <<
PPExtString(legalize(symName));
715 ps << PP::nbsp <<
":" << PP::end;
720 for (
auto param : params) {
722 ps <<
PPExtString(param.getName()) << PP::nbsp <<
"=" << PP::nbsp;
723 emitParamValue(param.getValue(), op);
737 return (
isExpression(op) && !isa<InvalidValueOp>(op)) ||
738 (isa<GenericIntrinsicOp>(op) && op->hasOneUse() &&
742void Emitter::emitStatementsInBlock(Block &block) {
743 for (
auto &bodyOp : block) {
744 if (encounteredError)
748 TypeSwitch<Operation *>(&bodyOp)
749 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
750 PrintFOp, FPrintFOp, FFlushOp, AssertOp, AssumeOp, CoverOp,
751 ConnectOp, MatchingConnectOp, PropAssignOp, InstanceOp,
752 InstanceChoiceOp, AttachOp, MemOp, InvalidValueOp, SeqMemOp,
753 CombMemOp, MemoryPortOp, MemoryDebugPortOp, MemoryPortAccessOp,
754 DomainDefineOp, RefDefineOp, RefForceOp, RefForceInitialOp,
755 RefReleaseOp, RefReleaseInitialOp, LayerBlockOp,
756 GenericIntrinsicOp, DomainCreateAnonOp>(
757 [&](
auto op) { emitStatement(op); })
758 .Default([&](
auto op) {
760 ps <<
"// operation " <<
PPExtString(op->getName().getStringRef());
762 emitOpError(op,
"not supported as statement");
767void Emitter::emitStatement(WhenOp op) {
770 emitExpression(op.getCondition());
772 emitLocationAndNewLine(op);
773 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
775 if (!op.hasElseRegion())
782 auto &elseBlock = op.getElseBlock();
783 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
784 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
785 emitStatement(whenOp);
792 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
795void Emitter::emitStatement(WireOp op) {
796 auto legalName = legalize(op.getNameAttr());
797 addForceable(op, legalName);
801 emitTypeWithColon(op.getResult().getType());
803 emitLocationAndNewLine(op);
806void Emitter::emitStatement(RegOp op) {
807 auto legalName = legalize(op.getNameAttr());
808 addForceable(op, legalName);
812 emitTypeWithColon(op.getResult().getType());
813 ps <<
"," << PP::space;
814 emitExpression(op.getClockVal());
816 emitLocationAndNewLine(op);
819void Emitter::emitStatement(RegResetOp op) {
820 auto legalName = legalize(op.getNameAttr());
821 addForceable(op, legalName);
825 ps <<
"regreset " << legalName;
826 emitTypeWithColon(op.getResult().getType());
827 ps <<
"," << PP::space;
828 emitExpression(op.getClockVal());
829 ps <<
"," << PP::space;
830 emitExpression(op.getResetSignal());
831 ps <<
"," << PP::space;
832 emitExpression(op.getResetValue());
836 ps <<
"reg " << legalName;
837 emitTypeWithColon(op.getResult().getType());
838 ps <<
"," << PP::space;
839 emitExpression(op.getClockVal());
840 ps << PP::space <<
"with :";
842 ps << PP::neverbreak;
845 ps <<
"reset => (" << PP::ibox0;
846 emitExpression(op.getResetSignal());
847 ps <<
"," << PP::space;
848 emitExpression(op.getResetValue());
849 ps <<
")" << PP::end;
852 emitLocationAndNewLine(op);
855void Emitter::emitStatement(NodeOp op) {
856 auto legalName = legalize(op.getNameAttr());
857 addForceable(op, legalName);
859 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(legalName); },
860 [&]() { emitExpression(op.getInput()); });
861 emitLocationAndNewLine(op);
864void Emitter::emitStatement(StopOp op) {
867 ps <<
"stop(" << PP::ibox0;
868 emitExpression(op.getClock());
869 ps <<
"," << PP::space;
870 emitExpression(op.getCond());
871 ps <<
"," << PP::space;
873 ps <<
")" << PP::end;
874 if (!op.getName().empty()) {
875 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
878 emitLocationAndNewLine(op);
881void Emitter::emitStatement(SkipOp op) {
884 emitLocationAndNewLine(op);
887void Emitter::emitFormatString(Operation *op, StringRef origFormatString,
888 OperandRange substitutionOperands,
889 llvm::SmallVectorImpl<Value> &substitutions) {
898 SmallString<64> formatString;
899 for (
size_t i = 0, e = origFormatString.size(), opIdx = 0; i != e; ++i) {
900 auto c = origFormatString[i];
903 formatString.push_back(c);
906 SmallString<6> width;
907 c = origFormatString[++i];
910 c = origFormatString[++i];
919 formatString.append(width);
922 substitutions.push_back(substitutionOperands[opIdx++]);
925 formatString.push_back(c);
930 if (origFormatString.slice(i, i + 4) ==
"{{}}") {
931 formatString.append(
"{{");
932 TypeSwitch<Operation *>(substitutionOperands[opIdx++].getDefiningOp())
934 [&](
auto time) { formatString.append(
"SimulationTime"); })
935 .Case<HierarchicalModuleNameOp>([&](
auto time) {
936 formatString.append(
"HierarchicalModuleName");
939 emitError(op,
"unsupported fstring substitution type");
941 formatString.append(
"}}");
946 formatString.push_back(c);
952void Emitter::emitStatement(PrintFOp op) {
955 ps <<
"printf(" << PP::ibox0;
956 emitExpression(op.getClock());
957 ps <<
"," << PP::space;
958 emitExpression(op.getCond());
959 ps <<
"," << PP::space;
961 SmallVector<Value, 4> substitutions;
962 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
964 for (
auto operand : substitutions) {
965 ps <<
"," << PP::space;
966 emitExpression(operand);
968 ps <<
")" << PP::end;
969 if (!op.getName().empty()) {
970 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
973 emitLocationAndNewLine(op);
976void Emitter::emitStatement(FPrintFOp op) {
979 ps <<
"fprintf(" << PP::ibox0;
980 emitExpression(op.getClock());
981 ps <<
"," << PP::space;
982 emitExpression(op.getCond());
983 ps <<
"," << PP::space;
985 SmallVector<Value, 4> outputFileSubstitutions;
986 emitFormatString(op, op.getOutputFile(), op.getOutputFileSubstitutions(),
987 outputFileSubstitutions);
988 if (!outputFileSubstitutions.empty()) {
989 ps <<
"," << PP::space;
990 interleaveComma(outputFileSubstitutions);
993 ps <<
"," << PP::space;
994 SmallVector<Value, 4> substitutions;
995 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
997 if (!substitutions.empty()) {
998 ps <<
"," << PP::space;
999 interleaveComma(substitutions);
1002 ps <<
")" << PP::end;
1003 if (!op.getName().empty()) {
1004 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1007 emitLocationAndNewLine(op);
1010void Emitter::emitStatement(FFlushOp op) {
1013 ps <<
"fflush(" << PP::ibox0;
1014 emitExpression(op.getClock());
1015 ps <<
"," << PP::space;
1016 emitExpression(op.getCond());
1017 if (op.getOutputFileAttr()) {
1018 ps <<
"," << PP::space;
1019 SmallVector<Value, 4> substitutions;
1020 emitFormatString(op, op.getOutputFileAttr(),
1021 op.getOutputFileSubstitutions(), substitutions);
1022 if (!substitutions.empty()) {
1023 ps <<
"," << PP::space;
1024 interleaveComma(substitutions);
1027 ps <<
")" << PP::end;
1029 emitLocationAndNewLine(op);
1033void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
1036 ps << mnemonic <<
"(" << PP::ibox0;
1037 emitExpression(op.getClock());
1038 ps <<
"," << PP::space;
1039 emitExpression(op.getPredicate());
1040 ps <<
"," << PP::space;
1041 emitExpression(op.getEnable());
1042 ps <<
"," << PP::space;
1044 ps <<
")" << PP::end;
1045 if (!op.getName().empty()) {
1046 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1049 emitLocationAndNewLine(op);
1052void Emitter::emitStatement(ConnectOp op) {
1056 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1057 ps <<
"invalidate" << PP::space;
1058 emitExpression(op.getDest());
1060 ps <<
"connect" << PP::space;
1061 emitExpression(op.getDest());
1062 ps <<
"," << PP::space;
1063 emitExpression(op.getSrc());
1067 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1068 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1070 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1073 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1076 emitLocationAndNewLine(op);
1079void Emitter::emitStatement(MatchingConnectOp op) {
1083 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1084 ps <<
"invalidate" << PP::space;
1085 emitExpression(op.getDest());
1087 ps <<
"connect" << PP::space;
1088 emitExpression(op.getDest());
1089 ps <<
"," << PP::space;
1090 emitExpression(op.getSrc());
1094 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1095 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1097 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1100 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1103 emitLocationAndNewLine(op);
1106void Emitter::emitStatement(PropAssignOp op) {
1109 ps <<
"propassign" << PP::space;
1110 interleaveComma(op.getOperands());
1112 emitLocationAndNewLine(op);
1115void Emitter::emitStatement(InstanceOp op) {
1117 auto legalName = legalize(op.getNameAttr());
1119 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
1120 emitLocationAndNewLine(op);
1124 SmallString<16> portName(legalName);
1125 portName.push_back(
'.');
1126 unsigned baseLen = portName.size();
1127 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1128 portName.append(legalize(op.getPortNameAttr(i)));
1129 addValueName(op.getResult(i), portName);
1130 portName.resize(baseLen);
1134void Emitter::emitStatement(InstanceChoiceOp op) {
1136 auto legalName = legalize(op.getNameAttr());
1137 ps <<
"instchoice " <<
PPExtString(legalName) <<
" of "
1138 <<
PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
1139 <<
PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
1142 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
1144 ps <<
PPExtString(legalize(optSym.getLeafReference()));
1149 setPendingNewline();
1151 SmallString<16> portName(legalName);
1152 portName.push_back(
'.');
1153 unsigned baseLen = portName.size();
1154 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1155 portName.append(legalize(op.getPortNameAttr(i)));
1156 addValueName(op.getResult(i), portName);
1157 portName.resize(baseLen);
1161void Emitter::emitStatement(AttachOp op) {
1162 emitStatementFunctionOp(
PPExtString(
"attach"), op);
1165void Emitter::emitStatement(MemOp op) {
1166 auto legalName = legalize(op.getNameAttr());
1167 SmallString<16> portName(legalName);
1168 portName.push_back(
'.');
1169 auto portNameBaseLen = portName.size();
1170 for (
auto result :
llvm::zip(op.getResults(), op.getPortNames())) {
1171 portName.resize(portNameBaseLen);
1172 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
1173 addValueName(std::get<0>(result), portName);
1178 emitLocationAndNewLine(op);
1181 ps <<
"data-type => ";
1182 emitType(op.getDataType());
1187 ps <<
"read-latency => ";
1190 ps <<
"write-latency => ";
1194 SmallString<16> reader, writer, readwriter;
1195 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
1196 auto add = [&](SmallString<16> &to, StringAttr name) {
1199 to.append(name.getValue());
1201 switch (port.second) {
1202 case MemOp::PortKind::Read:
1203 add(reader, legalize(port.first));
1205 case MemOp::PortKind::Write:
1206 add(writer, legalize(port.first));
1208 case MemOp::PortKind::ReadWrite:
1209 add(readwriter, legalize(port.first));
1211 case MemOp::PortKind::Debug:
1212 emitOpError(op,
"has unsupported 'debug' port");
1216 if (!reader.empty())
1217 ps <<
"reader => " << reader << PP::newline;
1218 if (!writer.empty())
1219 ps <<
"writer => " << writer << PP::newline;
1220 if (!readwriter.empty())
1221 ps <<
"readwriter => " << readwriter << PP::newline;
1223 ps <<
"read-under-write => ";
1224 emitAttribute(op.getRuwAttr());
1225 setPendingNewline();
1229void Emitter::emitStatement(SeqMemOp op) {
1232 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
1233 emitTypeWithColon(op.getType());
1234 ps <<
"," << PP::space;
1235 emitAttribute(op.getRuwAttr());
1237 emitLocationAndNewLine(op);
1240void Emitter::emitStatement(CombMemOp op) {
1243 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
1244 emitTypeWithColon(op.getType());
1246 emitLocationAndNewLine(op);
1249void Emitter::emitStatement(MemoryPortOp op) {
1251 addValueName(op.getData(), legalize(op.getNameAttr()));
1254void Emitter::emitStatement(MemoryDebugPortOp op) {
1256 addValueName(op.getData(), legalize(op.getNameAttr()));
1259void Emitter::emitStatement(MemoryPortAccessOp op) {
1263 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1264 emitAttribute(port.getDirection());
1266 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
1269 auto *mem = port.getMemory().getDefiningOp();
1270 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1271 ps << legalize(seqMem.getNameAttr());
1273 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1277 emitExpression(op.getIndex());
1281 emitExpression(op.getClock());
1283 emitLocationAndNewLine(op);
1286void Emitter::emitStatement(DomainDefineOp op) {
1288 if (isa_and_nonnull<DomainCreateAnonOp>(op.getSrc().getDefiningOp()))
1292 emitAssignLike([&]() { emitExpression(op.getDest()); },
1293 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1295 emitLocationAndNewLine(op);
1298void Emitter::emitStatement(RefDefineOp op) {
1300 emitAssignLike([&]() { emitExpression(op.getDest()); },
1301 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1303 emitLocationAndNewLine(op);
1306void Emitter::emitStatement(RefForceOp op) {
1307 emitStatementFunctionOp(
PPExtString(
"force"), op);
1310void Emitter::emitStatement(RefForceInitialOp op) {
1312 auto constantPredicate =
1313 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1314 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1317 emitExpression(op.getPredicate());
1318 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1320 ps <<
"force_initial(";
1322 interleaveComma({op.getDest(), op.getSrc()});
1327 emitLocationAndNewLine(op);
1330void Emitter::emitStatement(RefReleaseOp op) {
1331 emitStatementFunctionOp(
PPExtString(
"release"), op);
1334void Emitter::emitStatement(RefReleaseInitialOp op) {
1336 auto constantPredicate =
1337 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1338 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1341 emitExpression(op.getPredicate());
1342 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1344 ps <<
"release_initial(";
1345 emitExpression(op.getDest());
1349 emitLocationAndNewLine(op);
1352void Emitter::emitStatement(LayerBlockOp op) {
1354 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1355 emitLocationAndNewLine(op);
1356 auto *body = op.getBody();
1357 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1360void Emitter::emitStatement(InvalidValueOp op) {
1363 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1364 return use.getOperandNumber() == 1 &&
1365 isa<ConnectOp, MatchingConnectOp>(use.getOwner());
1371 auto name = circuitNamespace.newName(
"_invalid");
1372 addValueName(op, name);
1374 emitType(op.getType());
1375 emitLocationAndNewLine(op);
1381 emitLocationAndNewLine(op);
1384void Emitter::emitStatement(GenericIntrinsicOp op) {
1387 emitGenericIntrinsic(op);
1390 auto name = circuitNamespace.newName(
"_gen_int");
1391 addValueName(op.getResult(), name);
1392 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(name); },
1393 [&]() { emitGenericIntrinsic(op); });
1395 emitLocationAndNewLine(op);
1398void Emitter::emitStatement(DomainCreateAnonOp op) {
1402void Emitter::emitExpression(Value value) {
1405 if (
auto name = lookupEmittedName(value)) {
1411 auto op = value.getDefiningOp();
1412 assert(op &&
"value must either be a block arg or the result of an op");
1413 TypeSwitch<Operation *>(op)
1416 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1417 OpenSubfieldOp, OpenSubindexOp,
1419 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1420 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1421 EQPrimOp, NEQPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1423 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsClockPrimOp,
1424 CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp, XorRPrimOp,
1426 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1427 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1428 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1429 UnresolvedPathOp, GenericIntrinsicOp, CatPrimOp, UnsafeDomainCastOp,
1431 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp,
1433 TimeOp>([&](
auto op) {
1434 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1436 .Default([&](
auto op) {
1437 emitOpError(op,
"not supported as expression");
1438 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1443void Emitter::emitExpression(ConstantOp op) {
1445 emitType(op.getType(),
false);
1452void Emitter::emitExpression(SpecialConstantOp op) {
1453 auto emitInner = [&]() {
1460 .
Case<ClockType>([&](
auto type) {
1465 .Case<ResetType>([&](
auto type) { emitInner(); })
1466 .Case<AsyncResetType>([&](
auto type) {
1467 ps <<
"asAsyncReset(";
1474void Emitter::emitExpression(SubfieldOp op) {
1475 BundleType type = op.getInput().getType();
1476 emitExpression(op.getInput());
1477 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1481void Emitter::emitExpression(SubindexOp op) {
1482 emitExpression(op.getInput());
1489void Emitter::emitExpression(SubaccessOp op) {
1490 emitExpression(op.getInput());
1492 emitExpression(op.getIndex());
1496void Emitter::emitExpression(OpenSubfieldOp op) {
1497 auto type = op.getInput().getType();
1498 emitExpression(op.getInput());
1499 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1502void Emitter::emitExpression(OpenSubindexOp op) {
1503 emitExpression(op.getInput());
1509void Emitter::emitExpression(RefSendOp op) {
1511 emitExpression(op.getBase());
1515void Emitter::emitExpression(RefResolveOp op) {
1517 emitExpression(op.getRef());
1521void Emitter::emitExpression(RefSubOp op) {
1522 emitExpression(op.getInput());
1524 .
Case<FVectorType>([&](
auto type) {
1530 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1533void Emitter::emitExpression(RWProbeOp op) {
1537 auto target = symInfos->get().irn.lookup(op.getTarget());
1539 if (target.isPort()) {
1540 auto mod = cast<FModuleOp>(target.getOp());
1541 auto port = target.getPort();
1542 base = mod.getArgument(port);
1544 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1547 emitExpression(base);
1550 auto fieldID = target.getField();
1551 auto type = base.getType();
1554 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1555 auto index = vecTy.getIndexForFieldID(fieldID);
1559 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1561 fieldID = subfieldID;
1563 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1564 auto index = bundleTy.getIndexForFieldID(fieldID);
1565 ps <<
"." << bundleTy.getElementName(index);
1566 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1568 fieldID = subfieldID;
1574void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1576void Emitter::emitExpression(UninferredResetCastOp op) {
1577 emitExpression(op.getInput());
1580void Emitter::emitExpression(FIntegerConstantOp op) {
1586void Emitter::emitExpression(BoolConstantOp op) {
1587 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1590void Emitter::emitExpression(DoubleConstantOp op) {
1596 SmallString<16> str;
1597 op.getValueAttr().getValue().toString(str);
1602void Emitter::emitExpression(StringConstantOp op) {
1608void Emitter::emitExpression(ListCreateOp op) {
1609 return emitLiteralExpression(op.getType(), op.getElements());
1612void Emitter::emitExpression(UnresolvedPathOp op) {
1618void Emitter::emitExpression(GenericIntrinsicOp op) {
1619 emitGenericIntrinsic(op);
1622void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1624void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1625 ArrayRef<uint32_t> attrs) {
1626 ps << mnemonic <<
"(" << PP::ibox0;
1627 interleaveComma(op->getOperands());
1628 if (!op->getOperands().empty() && !attrs.empty())
1629 ps <<
"," << PP::space;
1630 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1631 ps <<
")" << PP::end;
1634void Emitter::emitExpression(CatPrimOp op) {
1635 size_t numOperands = op.getNumOperands();
1636 switch (numOperands) {
1639 emitType(op.getType(),
false);
1643 auto operand = op->getOperand(0);
1645 if (isa<UIntType>(operand.getType()))
1646 return emitExpression(operand);
1649 ps <<
"cat(" << PP::ibox0;
1650 emitExpression(op->getOperand(0));
1651 ps <<
"," << PP::space <<
"SInt<0>(0))" << PP::end;
1657 for (
size_t i = 0; i < numOperands - 1; ++i) {
1658 ps <<
"cat(" << PP::ibox0;
1659 emitExpression(op->getOperand(i));
1660 ps <<
"," << PP::space;
1663 emitExpression(op->getOperand(numOperands - 1));
1664 for (
size_t i = 0; i < numOperands - 1; ++i)
1665 ps <<
")" << PP::end;
1670void Emitter::emitExpression(UnsafeDomainCastOp op) {
1671 ps <<
"unsafe_domain_cast(" << PP::ibox0;
1672 interleaveComma(op.getOperands(),
1673 [&](Value operand) { emitExpression(operand); });
1674 ps <<
")" << PP::end;
1677void Emitter::emitAttribute(MemDirAttr attr) {
1679 case MemDirAttr::Infer:
1682 case MemDirAttr::Read:
1685 case MemDirAttr::Write:
1688 case MemDirAttr::ReadWrite:
1694void Emitter::emitAttribute(RUWBehaviorAttr attr) {
1695 switch (attr.getValue()) {
1696 case RUWBehavior::Undefined:
1699 case RUWBehavior::Old:
1702 case RUWBehavior::New:
1709void Emitter::emitType(Type type,
bool includeConst) {
1710 if (includeConst &&
isConst(type))
1712 auto emitWidth = [&](std::optional<int32_t> width) {
1721 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1722 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1723 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1724 .Case<UIntType>([&](
auto type) {
1726 emitWidth(type.getWidth());
1728 .Case<SIntType>([&](
auto type) {
1730 emitWidth(type.getWidth());
1732 .Case<AnalogType>([&](
auto type) {
1734 emitWidth(type.getWidth());
1736 .Case<OpenBundleType, BundleType>([&](
auto type) {
1738 if (!type.getElements().empty())
1740 bool anyEmitted =
false;
1742 for (
auto &element : type.getElements()) {
1744 ps <<
"," << PP::space;
1748 ps << legalize(element.name);
1749 emitTypeWithColon(element.type);
1758 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1759 emitType(type.getElementType());
1764 .Case<RefType>([&](RefType type) {
1765 if (type.getForceable())
1768 ps.
cbox(2, IndentStyle::Block);
1770 emitType(type.getType());
1771 if (
auto layer = type.getLayer()) {
1774 emitSymbol(type.getLayer());
1779 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1780 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1781 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1782 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1783 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1784 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1785 .Case<ListType>([&](ListType type) {
1787 emitType(type.getElementType());
1790 .Case<DomainType>([&](DomainType type) { ps <<
"Domain"; })
1791 .Default([&](
auto type) {
1792 llvm_unreachable(
"all types should be implemented");
1796void Emitter::emitDomains(Attribute attr, ArrayRef<PortInfo> ports) {
1799 if (
auto domains = dyn_cast<ArrayAttr>(attr)) {
1800 if (domains.empty())
1804 interleaveComma(domains, [&](Attribute attr) {
1806 ports[cast<IntegerAttr>(attr).getUInt()].name.getValue());
1811 auto kind = cast<FlatSymbolRefAttr>(attr);
1818void Emitter::emitLocation(Location loc) {
1820 ps << PP::neverbreak;
1822 dyn_cast_or_null<FileLineColLoc, LocationAttr>(LocationAttr(loc))) {
1823 ps <<
" @[" << fileLoc.getFilename().getValue();
1824 if (
auto line = fileLoc.getLine()) {
1827 if (
auto col = fileLoc.getColumn()) {
1844 std::optional<size_t> targetLineLength,
1846 Emitter emitter(os, version,
1847 targetLineLength.value_or(defaultTargetLineLength));
1848 for (
auto &op : *
module.getBody()) {
1849 if (auto circuitOp = dyn_cast<CircuitOp>(op))
1850 emitter.emitCircuit(circuitOp);
1852 return emitter.finalize();
1857 "target-line-length",
1858 llvm::cl::desc(
"Target line length for emitted .fir"),
1859 llvm::cl::value_desc(
"number of chars"),
1860 llvm::cl::init(defaultTargetLineLength));
1861 static mlir::TranslateFromMLIRRegistration toFIR(
1862 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
1863 [](ModuleOp module, llvm::raw_ostream &os) {
1866 [](mlir::DialectRegistry ®istry) {
1867 registry.insert<chirrtl::CHIRRTLDialect>();
1868 registry.insert<firrtl::FIRRTLDialect>();
assert(baseType &&"element must be base type")
#define HANDLE(OPTYPE, OPKIND)
static bool isEmittedInline(Operation *op)
Check if an operation is inlined into the emission of their users.
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Block * getBodyBlock(FModuleLike mod)
This class implements the same functionality as TypeSwitch except that it uses firrtl::type_dyn_cast ...
FIRRTLTypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
This class represents a collection of InnerSymbolTable's.
void space()
Add a breakable space.
void cbox(int32_t offset=0, IndentStyle style=IndentStyle::Visual)
Start a consistent group with specified offset.
void zerobreak()
Add a break that is zero-wide if not broken.
Wrap a PrettyPrinter with TokenBuilder features as well as operator<<'s.
auto scopedBox(T &&t, Callable &&c, Token close=EndToken())
Open a box, invoke the lambda, and close it after.
TokenStream & addAsString(T &&t)
General-purpose "format this" helper, for types not supported by operator<< yet.
TokenStream & writeQuotedEscaped(StringRef str, bool useHexEscapes=false, StringRef left="\"", StringRef right="\"")
PrettyPrinter::Listener that saves strings while live.
mlir::LogicalResult exportFIRFile(mlir::ModuleOp module, llvm::raw_ostream &os, std::optional< size_t > targetLineLength, FIRVersion version)
constexpr FIRVersion exportFIRVersion
The version of FIRRTL that the exporter produces.
void registerToFIRFileTranslation()
bool isConst(Type type)
Returns true if this is a 'const' type whose value is guaranteed to be unchanging at circuit executio...
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
The namespace of a CircuitOp, generally inhabited by modules.
The FIRRTL specification version.
This class represents the namespace in which InnerRef's can be resolved.
String wrapper to indicate string has external storage.