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 emitRequirements(ArrayRef<Attribute> requirements);
71 void emitParamAssign(ParamDeclAttr param, Operation *op,
72 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
73 void emitParamValue(Attribute value, Operation *op);
75 void emitGenericIntrinsic(GenericIntrinsicOp op);
78 void emitStatementsInBlock(
Block &block);
79 void emitStatement(WhenOp op);
80 void emitStatement(WireOp op);
81 void emitStatement(RegOp op);
82 void emitStatement(RegResetOp op);
83 void emitStatement(NodeOp op);
84 void emitStatement(StopOp op);
85 void emitStatement(SkipOp op);
86 void emitFormatString(Operation *op, StringRef formatString, OperandRange ops,
87 llvm::SmallVectorImpl<Value> &substitutions);
89 void emitPrintfLike(T op, StringAttr fileName);
90 void emitStatement(PrintFOp op);
91 void emitStatement(FPrintFOp op);
92 void emitStatement(FFlushOp op);
93 void emitStatement(ConnectOp op);
94 void emitStatement(MatchingConnectOp op);
95 void emitStatement(PropAssignOp op);
96 void emitStatement(InstanceOp op);
97 void emitStatement(InstanceChoiceOp op);
98 void emitStatement(AttachOp op);
99 void emitStatement(MemOp op);
100 void emitStatement(InvalidValueOp op);
101 void emitStatement(CombMemOp op);
102 void emitStatement(SeqMemOp op);
103 void emitStatement(MemoryPortOp op);
104 void emitStatement(MemoryDebugPortOp op);
105 void emitStatement(MemoryPortAccessOp op);
106 void emitStatement(DomainDefineOp op);
107 void emitStatement(RefDefineOp op);
108 void emitStatement(RefForceOp op);
109 void emitStatement(RefForceInitialOp op);
110 void emitStatement(RefReleaseOp op);
111 void emitStatement(RefReleaseInitialOp op);
112 void emitStatement(LayerBlockOp op);
113 void emitStatement(GenericIntrinsicOp op);
114 void emitStatement(DomainCreateAnonOp op);
117 void emitVerifStatement(T op, StringRef mnemonic);
118 void emitStatement(AssertOp op) { emitVerifStatement(op,
"assert"); }
119 void emitStatement(AssumeOp op) { emitVerifStatement(op,
"assume"); }
120 void emitStatement(CoverOp op) { emitVerifStatement(op,
"cover"); }
123 void emitExpression(Value value);
124 void emitExpression(ConstantOp op);
125 void emitExpression(SpecialConstantOp op);
126 void emitExpression(SubfieldOp op);
127 void emitExpression(SubindexOp op);
128 void emitExpression(SubaccessOp op);
129 void emitExpression(OpenSubfieldOp op);
130 void emitExpression(OpenSubindexOp op);
131 void emitExpression(RefResolveOp op);
132 void emitExpression(RefSendOp op);
133 void emitExpression(RefSubOp op);
134 void emitExpression(RWProbeOp op);
135 void emitExpression(RefCastOp op);
136 void emitExpression(UninferredResetCastOp op);
137 void emitExpression(ConstCastOp op);
138 void emitExpression(StringConstantOp op);
139 void emitExpression(FIntegerConstantOp op);
140 void emitExpression(BoolConstantOp op);
141 void emitExpression(DoubleConstantOp op);
142 void emitExpression(ListCreateOp op);
143 void emitExpression(UnresolvedPathOp op);
144 void emitExpression(GenericIntrinsicOp op);
145 void emitExpression(CatPrimOp op);
146 void emitExpression(UnsafeDomainCastOp op);
147 void emitExpression(UnknownValueOp op);
149 void emitPrimExpr(StringRef mnemonic, Operation *op,
150 ArrayRef<uint32_t> attrs = {});
152 void emitExpression(BitsPrimOp op) {
153 emitPrimExpr(
"bits", op, {op.getHi(), op.getLo()});
155 void emitExpression(HeadPrimOp op) {
156 emitPrimExpr(
"head", op, op.getAmount());
158 void emitExpression(TailPrimOp op) {
159 emitPrimExpr(
"tail", op, op.getAmount());
161 void emitExpression(PadPrimOp op) { emitPrimExpr(
"pad", op, op.getAmount()); }
162 void emitExpression(ShlPrimOp op) { emitPrimExpr(
"shl", op, op.getAmount()); }
163 void emitExpression(ShrPrimOp op) { emitPrimExpr(
"shr", op, op.getAmount()); }
165 void emitExpression(TimeOp op){};
168#define HANDLE(OPTYPE, MNEMONIC) \
169 void emitExpression(OPTYPE op) { emitPrimExpr(MNEMONIC, op); }
184 HANDLE(DShlPrimOp,
"dshl");
185 HANDLE(DShlwPrimOp,
"dshlw");
186 HANDLE(DShrPrimOp,
"dshr");
188 HANDLE(AsSIntPrimOp,
"asSInt");
189 HANDLE(AsUIntPrimOp,
"asUInt");
190 HANDLE(AsAsyncResetPrimOp,
"asAsyncReset");
191 HANDLE(AsClockPrimOp,
"asClock");
195 HANDLE(AndRPrimOp,
"andr");
197 HANDLE(XorRPrimOp,
"xorr");
201 void emitAttribute(MemDirAttr attr);
202 void emitAttribute(RUWBehaviorAttr attr);
205 void emitType(Type type,
bool includeConst =
true);
206 void emitTypeWithColon(Type type) {
207 ps << PP::space <<
":" << PP::nbsp;
212 void emitDomains(Attribute attr, ArrayRef<PortInfo> ports);
215 void emitLocation(Location loc);
216 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
217 template <
typename... Args>
218 void emitLocationAndNewLine(Args... args) {
221 ps << PP::neverbreak;
222 emitLocation(args...);
226 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
227 llvm::function_ref<
void()> emitRHS,
229 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
231 ps.scopedBox(PP::ibox2, [&]() {
233 ps << *wordBeforeLHS << PP::space;
237 ps << PP::space << syntax << PP::nbsp;
239 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
244 void emitSubExprIBox2(Value v) {
245 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
250 template <
typename Container,
typename EachFn>
251 void interleaveComma(
const Container &c, EachFn eachFn) {
252 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
257 void interleaveComma(ValueRange ops) {
258 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
261 void emitStatementFunctionOp(
PPExtString name, Operation *op) {
264 ps.scopedBox(PP::ibox0, [&]() {
265 interleaveComma(op->getOperands());
268 emitLocationAndNewLine(op);
271 template <
typename EachFn,
typename Range>
272 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
275 ps.scopedBox(PP::ibox0, [&]() {
276 interleaveComma(r, eachFn);
281 void emitLiteralExpression(Type type, ValueRange values) {
282 return emitLiteralExpression(type, values,
283 [&](Value v) { emitSubExprIBox2(v); });
287 void emitSymbol(SymbolRefAttr symbol) {
288 ps.ibox(2, IndentStyle::Block);
289 ps << symbol.getRootReference();
290 for (
auto nested : symbol.getNestedReferences()) {
293 ps << nested.getAttr();
300 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
301 encounteredError =
true;
302 return op->emitError(message);
306 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
307 encounteredError =
true;
308 return op->emitOpError(message);
313 std::optional<StringRef> lookupEmittedName(Value value) {
314 auto it = valueNames.find(value);
315 if (it != valueNames.end())
322 void emitPendingNewlineIfNeeded() {
323 if (pendingNewline) {
324 pendingNewline =
false;
328 void setPendingNewline() {
330 pendingNewline =
true;
333 void startStatement() { emitPendingNewlineIfNeeded(); }
351 bool pendingNewline =
false;
354 bool encounteredError =
false;
359 DenseMap<Value, StringRef> valueNames;
360 StringSet<> valueNamesStorage;
364 StringAttr legalize(StringAttr attr) {
365 StringRef str = attr.getValue();
366 if (str.empty() || !
isdigit(str.front()))
368 return StringAttr::get(attr.getContext(),
"`" + Twine(attr) +
"`");
371 void addValueName(Value value, StringAttr attr) {
372 valueNames.insert({value, attr.getValue()});
374 void addValueName(Value value, StringRef str) {
375 auto it = valueNamesStorage.insert(str);
376 valueNames.insert({value, it.first->getKey()});
378 void addForceable(Forceable op, StringAttr attr) {
379 addValueName(op.getData(), attr);
380 if (op.isForceable()) {
381 SmallString<32> rwName;
382 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
383 addValueName(op.getDataRef(), rwName);
392 SymbolTable symbolTable;
395 SymInfos(Operation *op) : symbolTable(op), istc(op){};
397 std::optional<std::reference_wrapper<SymInfos>> symInfos;
404LogicalResult Emitter::finalize() {
return failure(encounteredError); }
407void Emitter::emitCircuit(CircuitOp op) {
408 circuitNamespace.add(op);
409 SymInfos circuitSymInfos(op);
410 symInfos = circuitSymInfos;
412 ps <<
"FIRRTL version ";
419 ps <<
"circuit " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
423 if (encounteredError)
425 TypeSwitch<Operation *>(&bodyOp)
426 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](
auto op) {
430 .Case<DomainOp, LayerOp, OptionOp, FormalOp, SimulationOp>(
431 [&](
auto op) { emitDeclaration(op); })
432 .Default([&](
auto op) {
433 emitOpError(op,
"not supported for emission inside circuit");
437 circuitNamespace.clear();
438 symInfos = std::nullopt;
441void Emitter::emitEnabledLayers(ArrayRef<Attribute> layers) {
442 for (
auto layer : layers) {
444 ps.
cbox(2, IndentStyle::Block);
445 ps <<
"enablelayer" << PP::space;
446 emitSymbol(cast<SymbolRefAttr>(layer));
451void Emitter::emitKnownLayers(ArrayRef<Attribute> layers) {
452 for (
auto layer : layers) {
454 ps.
cbox(2, IndentStyle::Block);
455 ps <<
"knownlayer" << PP::space;
456 emitSymbol(cast<SymbolRefAttr>(layer));
461void Emitter::emitRequirements(ArrayRef<Attribute> requirements) {
462 if (requirements.empty())
465 ps.
cbox(2, IndentStyle::Block);
466 ps <<
"requires" << PP::space;
467 llvm::interleaveComma(requirements, ps, [&](Attribute req) {
473void Emitter::emitParamAssign(ParamDeclAttr param, Operation *op,
474 std::optional<PPExtString> wordBeforeLHS) {
476 ps << *wordBeforeLHS << PP::nbsp;
478 ps <<
PPExtString(param.getName().strref()) << PP::nbsp <<
"=" << PP::nbsp;
479 emitParamValue(param.getValue(), op);
482void Emitter::emitParamValue(Attribute value, Operation *op) {
483 TypeSwitch<Attribute>(value)
484 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
485 .Case<FloatAttr>([&](
auto attr) {
487 attr.getValue().toString(str);
492 .Case<ArrayAttr>([&](
auto attr) {
495 interleaveComma(attr.getValue(),
496 [&](
auto element) { emitParamValue(element, op); });
500 .Case<DictionaryAttr>([&](
auto attr) {
503 interleaveComma(attr.getValue(), [&](
auto field) {
504 ps << PPExtString(field.getName()) << PP::nbsp <<
"=" << PP::nbsp;
505 emitParamValue(field.getValue(), op);
510 .Default([&](
auto attr) {
511 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
512 ps <<
"<unsupported-attr ";
518void Emitter::emitGenericIntrinsic(GenericIntrinsicOp op) {
522 ps << op.getIntrinsic();
524 auto params = op.getParameters();
525 if (!params.empty()) {
527 ps.scopedBox(PP::ibox0, [&]() {
529 params.getAsRange<ParamDeclAttr>(),
530 [&](ParamDeclAttr param) { emitParamAssign(param, op); });
535 if (op.getNumResults() != 0)
536 emitTypeWithColon(op.getResult().getType());
538 if (op.getNumOperands() != 0) {
539 ps <<
"," << PP::space;
540 ps.
scopedBox(PP::ibox0, [&]() { interleaveComma(op->getOperands()); });
547void Emitter::emitModule(FModuleOp op) {
549 ps.
cbox(4, IndentStyle::Block);
551 ps <<
"public" << PP::nbsp;
552 ps <<
"module " <<
PPExtString(legalize(op.getNameAttr()));
553 emitEnabledLayers(op.getLayers());
554 ps << PP::nbsp <<
":" << PP::end;
561 auto ports = op.getPorts();
562 emitModulePorts(ports, op.getArguments());
563 if (!ports.empty() && !op.getBodyBlock()->empty())
567 emitStatementsInBlock(*op.getBodyBlock());
570 valueNamesStorage.clear();
574void Emitter::emitModule(FExtModuleOp op) {
576 ps.
cbox(4, IndentStyle::Block);
577 ps <<
"extmodule " <<
PPExtString(legalize(op.getNameAttr()));
578 emitKnownLayers(op.getKnownLayers());
579 emitEnabledLayers(op.getLayers());
580 if (
auto reqs = op.getExternalRequirements())
581 emitRequirements(reqs.getValue());
582 ps << PP::nbsp <<
":" << PP::end;
589 auto ports = op.getPorts();
590 emitModulePorts(ports);
593 if (op.getDefname() && !op.getDefname()->empty()) {
595 ps <<
"defname = " <<
PPExtString(*op.getDefname());
600 emitModuleParameters(op, op.getParameters());
605void Emitter::emitModule(FIntModuleOp op) {
607 ps.
cbox(4, IndentStyle::Block);
608 ps <<
"intmodule " <<
PPExtString(legalize(op.getNameAttr()));
609 emitEnabledLayers(op.getLayers());
610 ps << PP::nbsp <<
":" << PP::end;
617 auto ports = op.getPorts();
618 emitModulePorts(ports);
621 ps <<
"intrinsic = " <<
PPExtString(op.getIntrinsic());
625 emitModuleParameters(op, op.getParameters());
632void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
633 Block::BlockArgListType arguments) {
635 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
637 const auto &port = ports[i];
638 ps << (port.direction == Direction::In ?
"input " :
"output ");
639 auto legalName = legalize(port.name);
640 if (!arguments.empty())
641 addValueName(arguments[i], legalName);
644 emitDomains(port.domains, ports);
645 emitLocation(ports[i].loc);
650void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
651 for (
auto param : parameters.getAsRange<ParamDeclAttr>()) {
653 emitParamAssign(param, op,
PPExtString(
"parameter"));
658void Emitter::emitDeclaration(DomainOp op) {
660 ps <<
"domain " <<
PPExtString(op.getSymName()) <<
" :";
661 emitLocationAndNewLine(op);
663 for (
auto attr : op.getFields()) {
664 auto fieldAttr = cast<DomainFieldAttr>(attr);
665 ps << PP::newline <<
PPExtString(fieldAttr.getName()) <<
" : ";
666 emitType(fieldAttr.getType());
672void Emitter::emitDeclaration(LayerOp op) {
674 ps <<
"layer " <<
PPExtString(op.getSymName()) <<
", "
675 <<
PPExtString(stringifyLayerConvention(op.getConvention()));
677 if (
auto outputFile = op->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
683 emitLocationAndNewLine(op);
685 for (
auto &bodyOp : op.getBody().getOps()) {
686 TypeSwitch<Operation *>(&bodyOp)
687 .Case<LayerOp>([&](
auto op) { emitDeclaration(op); })
688 .Default([&](
auto op) {
690 "not supported for emission inside layer definition");
697void Emitter::emitDeclaration(OptionOp op) {
699 ps <<
"option " <<
PPExtString(legalize(op.getSymNameAttr())) <<
" :";
702 for (
auto caseOp : op.getBody().getOps<OptionCaseOp>()) {
704 ps <<
PPExtString(legalize(caseOp.getSymNameAttr()));
705 emitLocation(caseOp);
708 ps << PP::newline << PP::newline;
712void Emitter::emitDeclaration(FormalOp op) {
713 emitFormalLike(op,
"formal", op.getSymNameAttr(),
714 op.getModuleNameAttr().getAttr(), op.getParameters());
718void Emitter::emitDeclaration(SimulationOp op) {
719 emitFormalLike(op,
"simulation", op.getSymNameAttr(),
720 op.getModuleNameAttr().getAttr(), op.getParameters());
724void Emitter::emitFormalLike(Operation *op, StringRef keyword,
725 StringAttr symName, StringAttr moduleName,
726 DictionaryAttr params) {
728 ps.
cbox(4, IndentStyle::Block);
729 ps << keyword <<
" " <<
PPExtString(legalize(symName));
731 ps << PP::nbsp <<
":" << PP::end;
736 for (
auto param : params) {
738 ps <<
PPExtString(param.getName()) << PP::nbsp <<
"=" << PP::nbsp;
739 emitParamValue(param.getValue(), op);
753 return (
isExpression(op) && !isa<InvalidValueOp>(op)) ||
754 (isa<GenericIntrinsicOp>(op) && op->hasOneUse() &&
758void Emitter::emitStatementsInBlock(Block &block) {
759 for (
auto &bodyOp : block) {
760 if (encounteredError)
764 TypeSwitch<Operation *>(&bodyOp)
765 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
766 PrintFOp, FPrintFOp, FFlushOp, AssertOp, AssumeOp, CoverOp,
767 ConnectOp, MatchingConnectOp, PropAssignOp, InstanceOp,
768 InstanceChoiceOp, AttachOp, MemOp, InvalidValueOp, SeqMemOp,
769 CombMemOp, MemoryPortOp, MemoryDebugPortOp, MemoryPortAccessOp,
770 DomainDefineOp, RefDefineOp, RefForceOp, RefForceInitialOp,
771 RefReleaseOp, RefReleaseInitialOp, LayerBlockOp,
772 GenericIntrinsicOp, DomainCreateAnonOp>(
773 [&](
auto op) { emitStatement(op); })
774 .Default([&](
auto op) {
776 ps <<
"// operation " <<
PPExtString(op->getName().getStringRef());
778 emitOpError(op,
"not supported as statement");
783void Emitter::emitStatement(WhenOp op) {
786 emitExpression(op.getCondition());
788 emitLocationAndNewLine(op);
789 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
791 if (!op.hasElseRegion())
798 auto &elseBlock = op.getElseBlock();
799 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
800 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
801 emitStatement(whenOp);
808 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
811void Emitter::emitStatement(WireOp op) {
812 auto legalName = legalize(op.getNameAttr());
813 addForceable(op, legalName);
817 emitTypeWithColon(op.getResult().getType());
819 emitLocationAndNewLine(op);
822void Emitter::emitStatement(RegOp op) {
823 auto legalName = legalize(op.getNameAttr());
824 addForceable(op, legalName);
828 emitTypeWithColon(op.getResult().getType());
829 ps <<
"," << PP::space;
830 emitExpression(op.getClockVal());
832 emitLocationAndNewLine(op);
835void Emitter::emitStatement(RegResetOp op) {
836 auto legalName = legalize(op.getNameAttr());
837 addForceable(op, legalName);
841 ps <<
"regreset " << legalName;
842 emitTypeWithColon(op.getResult().getType());
843 ps <<
"," << PP::space;
844 emitExpression(op.getClockVal());
845 ps <<
"," << PP::space;
846 emitExpression(op.getResetSignal());
847 ps <<
"," << PP::space;
848 emitExpression(op.getResetValue());
852 ps <<
"reg " << legalName;
853 emitTypeWithColon(op.getResult().getType());
854 ps <<
"," << PP::space;
855 emitExpression(op.getClockVal());
856 ps << PP::space <<
"with :";
858 ps << PP::neverbreak;
861 ps <<
"reset => (" << PP::ibox0;
862 emitExpression(op.getResetSignal());
863 ps <<
"," << PP::space;
864 emitExpression(op.getResetValue());
865 ps <<
")" << PP::end;
868 emitLocationAndNewLine(op);
871void Emitter::emitStatement(NodeOp op) {
872 auto legalName = legalize(op.getNameAttr());
873 addForceable(op, legalName);
875 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(legalName); },
876 [&]() { emitExpression(op.getInput()); });
877 emitLocationAndNewLine(op);
880void Emitter::emitStatement(StopOp op) {
883 ps <<
"stop(" << PP::ibox0;
884 emitExpression(op.getClock());
885 ps <<
"," << PP::space;
886 emitExpression(op.getCond());
887 ps <<
"," << PP::space;
889 ps <<
")" << PP::end;
890 if (!op.getName().empty()) {
891 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
894 emitLocationAndNewLine(op);
897void Emitter::emitStatement(SkipOp op) {
900 emitLocationAndNewLine(op);
903void Emitter::emitFormatString(Operation *op, StringRef origFormatString,
904 OperandRange substitutionOperands,
905 llvm::SmallVectorImpl<Value> &substitutions) {
914 SmallString<64> formatString;
915 for (
size_t i = 0, e = origFormatString.size(), opIdx = 0; i != e; ++i) {
916 auto c = origFormatString[i];
919 formatString.push_back(c);
922 SmallString<6> width;
923 c = origFormatString[++i];
926 c = origFormatString[++i];
935 formatString.append(width);
938 substitutions.push_back(substitutionOperands[opIdx++]);
941 formatString.push_back(c);
946 if (origFormatString.slice(i, i + 4) ==
"{{}}") {
947 formatString.append(
"{{");
948 TypeSwitch<Operation *>(substitutionOperands[opIdx++].getDefiningOp())
950 [&](
auto time) { formatString.append(
"SimulationTime"); })
951 .Case<HierarchicalModuleNameOp>([&](
auto time) {
952 formatString.append(
"HierarchicalModuleName");
955 emitError(op,
"unsupported fstring substitution type");
957 formatString.append(
"}}");
962 formatString.push_back(c);
968void Emitter::emitStatement(PrintFOp op) {
971 ps <<
"printf(" << PP::ibox0;
972 emitExpression(op.getClock());
973 ps <<
"," << PP::space;
974 emitExpression(op.getCond());
975 ps <<
"," << PP::space;
977 SmallVector<Value, 4> substitutions;
978 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
980 for (
auto operand : substitutions) {
981 ps <<
"," << PP::space;
982 emitExpression(operand);
984 ps <<
")" << PP::end;
985 if (!op.getName().empty()) {
986 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
989 emitLocationAndNewLine(op);
992void Emitter::emitStatement(FPrintFOp op) {
995 ps <<
"fprintf(" << PP::ibox0;
996 emitExpression(op.getClock());
997 ps <<
"," << PP::space;
998 emitExpression(op.getCond());
999 ps <<
"," << PP::space;
1001 SmallVector<Value, 4> outputFileSubstitutions;
1002 emitFormatString(op, op.getOutputFile(), op.getOutputFileSubstitutions(),
1003 outputFileSubstitutions);
1004 if (!outputFileSubstitutions.empty()) {
1005 ps <<
"," << PP::space;
1006 interleaveComma(outputFileSubstitutions);
1009 ps <<
"," << PP::space;
1010 SmallVector<Value, 4> substitutions;
1011 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
1013 if (!substitutions.empty()) {
1014 ps <<
"," << PP::space;
1015 interleaveComma(substitutions);
1018 ps <<
")" << PP::end;
1019 if (!op.getName().empty()) {
1020 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1023 emitLocationAndNewLine(op);
1026void Emitter::emitStatement(FFlushOp op) {
1029 ps <<
"fflush(" << PP::ibox0;
1030 emitExpression(op.getClock());
1031 ps <<
"," << PP::space;
1032 emitExpression(op.getCond());
1033 if (op.getOutputFileAttr()) {
1034 ps <<
"," << PP::space;
1035 SmallVector<Value, 4> substitutions;
1036 emitFormatString(op, op.getOutputFileAttr(),
1037 op.getOutputFileSubstitutions(), substitutions);
1038 if (!substitutions.empty()) {
1039 ps <<
"," << PP::space;
1040 interleaveComma(substitutions);
1043 ps <<
")" << PP::end;
1045 emitLocationAndNewLine(op);
1049void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
1052 ps << mnemonic <<
"(" << PP::ibox0;
1053 emitExpression(op.getClock());
1054 ps <<
"," << PP::space;
1055 emitExpression(op.getPredicate());
1056 ps <<
"," << PP::space;
1057 emitExpression(op.getEnable());
1058 ps <<
"," << PP::space;
1060 ps <<
")" << PP::end;
1061 if (!op.getName().empty()) {
1062 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1065 emitLocationAndNewLine(op);
1068void Emitter::emitStatement(ConnectOp op) {
1072 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1073 ps <<
"invalidate" << PP::space;
1074 emitExpression(op.getDest());
1076 ps <<
"connect" << PP::space;
1077 emitExpression(op.getDest());
1078 ps <<
"," << PP::space;
1079 emitExpression(op.getSrc());
1083 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1084 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1086 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1089 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1092 emitLocationAndNewLine(op);
1095void Emitter::emitStatement(MatchingConnectOp op) {
1099 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1100 ps <<
"invalidate" << PP::space;
1101 emitExpression(op.getDest());
1103 ps <<
"connect" << PP::space;
1104 emitExpression(op.getDest());
1105 ps <<
"," << PP::space;
1106 emitExpression(op.getSrc());
1110 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1111 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1113 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1116 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1119 emitLocationAndNewLine(op);
1122void Emitter::emitStatement(PropAssignOp op) {
1125 ps <<
"propassign" << PP::space;
1126 interleaveComma(op.getOperands());
1128 emitLocationAndNewLine(op);
1131void Emitter::emitStatement(InstanceOp op) {
1133 auto legalName = legalize(op.getNameAttr());
1135 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
1136 emitLocationAndNewLine(op);
1140 SmallString<16> portName(legalName);
1141 portName.push_back(
'.');
1142 unsigned baseLen = portName.size();
1143 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1144 portName.append(legalize(op.getPortNameAttr(i)));
1145 addValueName(op.getResult(i), portName);
1146 portName.resize(baseLen);
1150void Emitter::emitStatement(InstanceChoiceOp op) {
1152 auto legalName = legalize(op.getNameAttr());
1153 ps <<
"instchoice " <<
PPExtString(legalName) <<
" of "
1154 <<
PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
1155 <<
PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
1158 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
1160 ps <<
PPExtString(legalize(optSym.getLeafReference()));
1165 setPendingNewline();
1167 SmallString<16> portName(legalName);
1168 portName.push_back(
'.');
1169 unsigned baseLen = portName.size();
1170 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1171 portName.append(legalize(op.getPortNameAttr(i)));
1172 addValueName(op.getResult(i), portName);
1173 portName.resize(baseLen);
1177void Emitter::emitStatement(AttachOp op) {
1178 emitStatementFunctionOp(
PPExtString(
"attach"), op);
1181void Emitter::emitStatement(MemOp op) {
1182 auto legalName = legalize(op.getNameAttr());
1183 SmallString<16> portName(legalName);
1184 portName.push_back(
'.');
1185 auto portNameBaseLen = portName.size();
1186 for (
auto result :
llvm::zip(op.getResults(), op.getPortNames())) {
1187 portName.resize(portNameBaseLen);
1188 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
1189 addValueName(std::get<0>(result), portName);
1194 emitLocationAndNewLine(op);
1197 ps <<
"data-type => ";
1198 emitType(op.getDataType());
1203 ps <<
"read-latency => ";
1206 ps <<
"write-latency => ";
1210 SmallString<16> reader, writer, readwriter;
1211 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
1212 auto add = [&](SmallString<16> &to, StringAttr name) {
1215 to.append(name.getValue());
1217 switch (port.second) {
1218 case MemOp::PortKind::Read:
1219 add(reader, legalize(port.first));
1221 case MemOp::PortKind::Write:
1222 add(writer, legalize(port.first));
1224 case MemOp::PortKind::ReadWrite:
1225 add(readwriter, legalize(port.first));
1227 case MemOp::PortKind::Debug:
1228 emitOpError(op,
"has unsupported 'debug' port");
1232 if (!reader.empty())
1233 ps <<
"reader => " << reader << PP::newline;
1234 if (!writer.empty())
1235 ps <<
"writer => " << writer << PP::newline;
1236 if (!readwriter.empty())
1237 ps <<
"readwriter => " << readwriter << PP::newline;
1239 ps <<
"read-under-write => ";
1240 emitAttribute(op.getRuwAttr());
1241 setPendingNewline();
1245void Emitter::emitStatement(SeqMemOp op) {
1248 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
1249 emitTypeWithColon(op.getType());
1250 ps <<
"," << PP::space;
1251 emitAttribute(op.getRuwAttr());
1253 emitLocationAndNewLine(op);
1256void Emitter::emitStatement(CombMemOp op) {
1259 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
1260 emitTypeWithColon(op.getType());
1262 emitLocationAndNewLine(op);
1265void Emitter::emitStatement(MemoryPortOp op) {
1267 addValueName(op.getData(), legalize(op.getNameAttr()));
1270void Emitter::emitStatement(MemoryDebugPortOp op) {
1272 addValueName(op.getData(), legalize(op.getNameAttr()));
1275void Emitter::emitStatement(MemoryPortAccessOp op) {
1279 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1280 emitAttribute(port.getDirection());
1282 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
1285 auto *mem = port.getMemory().getDefiningOp();
1286 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1287 ps << legalize(seqMem.getNameAttr());
1289 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1293 emitExpression(op.getIndex());
1297 emitExpression(op.getClock());
1299 emitLocationAndNewLine(op);
1302void Emitter::emitStatement(DomainDefineOp op) {
1304 if (isa_and_nonnull<DomainCreateAnonOp>(op.getSrc().getDefiningOp()))
1308 emitAssignLike([&]() { emitExpression(op.getDest()); },
1309 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1311 emitLocationAndNewLine(op);
1314void Emitter::emitStatement(RefDefineOp op) {
1316 emitAssignLike([&]() { emitExpression(op.getDest()); },
1317 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1319 emitLocationAndNewLine(op);
1322void Emitter::emitStatement(RefForceOp op) {
1323 emitStatementFunctionOp(
PPExtString(
"force"), op);
1326void Emitter::emitStatement(RefForceInitialOp op) {
1328 auto constantPredicate =
1329 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1330 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1333 emitExpression(op.getPredicate());
1334 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1336 ps <<
"force_initial(";
1338 interleaveComma({op.getDest(), op.getSrc()});
1343 emitLocationAndNewLine(op);
1346void Emitter::emitStatement(RefReleaseOp op) {
1347 emitStatementFunctionOp(
PPExtString(
"release"), op);
1350void Emitter::emitStatement(RefReleaseInitialOp op) {
1352 auto constantPredicate =
1353 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1354 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1357 emitExpression(op.getPredicate());
1358 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1360 ps <<
"release_initial(";
1361 emitExpression(op.getDest());
1365 emitLocationAndNewLine(op);
1368void Emitter::emitStatement(LayerBlockOp op) {
1370 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1371 emitLocationAndNewLine(op);
1372 auto *body = op.getBody();
1373 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1376void Emitter::emitStatement(InvalidValueOp op) {
1379 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1380 return use.getOperandNumber() == 1 &&
1381 isa<ConnectOp, MatchingConnectOp>(use.getOwner());
1387 auto name = circuitNamespace.newName(
"_invalid");
1388 addValueName(op, name);
1390 emitType(op.getType());
1391 emitLocationAndNewLine(op);
1397 emitLocationAndNewLine(op);
1400void Emitter::emitStatement(GenericIntrinsicOp op) {
1403 emitGenericIntrinsic(op);
1406 auto name = circuitNamespace.newName(
"_gen_int");
1407 addValueName(op.getResult(), name);
1408 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(name); },
1409 [&]() { emitGenericIntrinsic(op); });
1411 emitLocationAndNewLine(op);
1414void Emitter::emitStatement(DomainCreateAnonOp op) {
1418void Emitter::emitExpression(Value value) {
1421 if (
auto name = lookupEmittedName(value)) {
1427 auto op = value.getDefiningOp();
1428 assert(op &&
"value must either be a block arg or the result of an op");
1429 TypeSwitch<Operation *>(op)
1432 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1433 OpenSubfieldOp, OpenSubindexOp,
1435 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1436 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1437 EQPrimOp, NEQPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1439 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsClockPrimOp,
1440 CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp, XorRPrimOp,
1442 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1443 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1444 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1445 UnresolvedPathOp, GenericIntrinsicOp, CatPrimOp, UnsafeDomainCastOp,
1448 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp,
1450 TimeOp>([&](
auto op) {
1451 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1453 .Default([&](
auto op) {
1454 emitOpError(op,
"not supported as expression");
1455 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1460void Emitter::emitExpression(ConstantOp op) {
1462 emitType(op.getType(),
false);
1469void Emitter::emitExpression(SpecialConstantOp op) {
1470 auto emitInner = [&]() {
1477 .
Case<ClockType>([&](
auto type) {
1482 .Case<ResetType>([&](
auto type) { emitInner(); })
1483 .Case<AsyncResetType>([&](
auto type) {
1484 ps <<
"asAsyncReset(";
1491void Emitter::emitExpression(SubfieldOp op) {
1492 BundleType type = op.getInput().getType();
1493 emitExpression(op.getInput());
1494 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1498void Emitter::emitExpression(SubindexOp op) {
1499 emitExpression(op.getInput());
1506void Emitter::emitExpression(SubaccessOp op) {
1507 emitExpression(op.getInput());
1509 emitExpression(op.getIndex());
1513void Emitter::emitExpression(OpenSubfieldOp op) {
1514 auto type = op.getInput().getType();
1515 emitExpression(op.getInput());
1516 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1519void Emitter::emitExpression(OpenSubindexOp op) {
1520 emitExpression(op.getInput());
1526void Emitter::emitExpression(RefSendOp op) {
1528 emitExpression(op.getBase());
1532void Emitter::emitExpression(RefResolveOp op) {
1534 emitExpression(op.getRef());
1538void Emitter::emitExpression(RefSubOp op) {
1539 emitExpression(op.getInput());
1541 .
Case<FVectorType>([&](
auto type) {
1547 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1550void Emitter::emitExpression(RWProbeOp op) {
1554 auto target = symInfos->get().irn.lookup(op.getTarget());
1556 if (target.isPort()) {
1557 auto mod = cast<FModuleOp>(target.getOp());
1558 auto port = target.getPort();
1559 base = mod.getArgument(port);
1561 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1564 emitExpression(base);
1567 auto fieldID = target.getField();
1568 auto type = base.getType();
1571 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1572 auto index = vecTy.getIndexForFieldID(fieldID);
1576 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1578 fieldID = subfieldID;
1580 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1581 auto index = bundleTy.getIndexForFieldID(fieldID);
1582 ps <<
"." << bundleTy.getElementName(index);
1583 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1585 fieldID = subfieldID;
1591void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1593void Emitter::emitExpression(UninferredResetCastOp op) {
1594 emitExpression(op.getInput());
1597void Emitter::emitExpression(FIntegerConstantOp op) {
1603void Emitter::emitExpression(BoolConstantOp op) {
1604 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1607void Emitter::emitExpression(DoubleConstantOp op) {
1613 SmallString<16> str;
1614 op.getValueAttr().getValue().toString(str);
1619void Emitter::emitExpression(StringConstantOp op) {
1625void Emitter::emitExpression(ListCreateOp op) {
1626 return emitLiteralExpression(op.getType(), op.getElements());
1629void Emitter::emitExpression(UnresolvedPathOp op) {
1635void Emitter::emitExpression(GenericIntrinsicOp op) {
1636 emitGenericIntrinsic(op);
1639void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1641void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1642 ArrayRef<uint32_t> attrs) {
1643 ps << mnemonic <<
"(" << PP::ibox0;
1644 interleaveComma(op->getOperands());
1645 if (!op->getOperands().empty() && !attrs.empty())
1646 ps <<
"," << PP::space;
1647 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1648 ps <<
")" << PP::end;
1651void Emitter::emitExpression(CatPrimOp op) {
1652 size_t numOperands = op.getNumOperands();
1653 switch (numOperands) {
1656 emitType(op.getType(),
false);
1660 auto operand = op->getOperand(0);
1662 if (isa<UIntType>(operand.getType()))
1663 return emitExpression(operand);
1666 ps <<
"cat(" << PP::ibox0;
1667 emitExpression(op->getOperand(0));
1668 ps <<
"," << PP::space <<
"SInt<0>(0))" << PP::end;
1674 for (
size_t i = 0; i < numOperands - 1; ++i) {
1675 ps <<
"cat(" << PP::ibox0;
1676 emitExpression(op->getOperand(i));
1677 ps <<
"," << PP::space;
1680 emitExpression(op->getOperand(numOperands - 1));
1681 for (
size_t i = 0; i < numOperands - 1; ++i)
1682 ps <<
")" << PP::end;
1687void Emitter::emitExpression(UnsafeDomainCastOp op) {
1688 ps <<
"unsafe_domain_cast(" << PP::ibox0;
1689 interleaveComma(op.getOperands(),
1690 [&](Value operand) { emitExpression(operand); });
1691 ps <<
")" << PP::end;
1694void Emitter::emitExpression(UnknownValueOp op) {
1696 emitTypeWithColon(op.getType());
1699void Emitter::emitAttribute(MemDirAttr attr) {
1701 case MemDirAttr::Infer:
1704 case MemDirAttr::Read:
1707 case MemDirAttr::Write:
1710 case MemDirAttr::ReadWrite:
1716void Emitter::emitAttribute(RUWBehaviorAttr attr) {
1717 switch (attr.getValue()) {
1718 case RUWBehavior::Undefined:
1721 case RUWBehavior::Old:
1724 case RUWBehavior::New:
1731void Emitter::emitType(Type type,
bool includeConst) {
1732 if (includeConst &&
isConst(type))
1734 auto emitWidth = [&](std::optional<int32_t> width) {
1743 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1744 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1745 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1746 .Case<UIntType>([&](
auto type) {
1748 emitWidth(type.getWidth());
1750 .Case<SIntType>([&](
auto type) {
1752 emitWidth(type.getWidth());
1754 .Case<AnalogType>([&](
auto type) {
1756 emitWidth(type.getWidth());
1758 .Case<OpenBundleType, BundleType>([&](
auto type) {
1760 if (!type.getElements().empty())
1762 bool anyEmitted =
false;
1764 for (
auto &element : type.getElements()) {
1766 ps <<
"," << PP::space;
1770 ps << legalize(element.name);
1771 emitTypeWithColon(element.type);
1780 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1781 emitType(type.getElementType());
1786 .Case<RefType>([&](RefType type) {
1787 if (type.getForceable())
1790 ps.
cbox(2, IndentStyle::Block);
1792 emitType(type.getType());
1793 if (
auto layer = type.getLayer()) {
1796 emitSymbol(type.getLayer());
1801 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1802 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1803 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1804 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1805 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1806 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1807 .Case<ListType>([&](ListType type) {
1809 emitType(type.getElementType());
1812 .Case<DomainType>([&](DomainType type) { ps <<
"Domain"; })
1813 .Default([&](
auto type) {
1814 llvm_unreachable(
"all types should be implemented");
1818void Emitter::emitDomains(Attribute attr, ArrayRef<PortInfo> ports) {
1821 if (
auto domains = dyn_cast<ArrayAttr>(attr)) {
1822 if (domains.empty())
1826 interleaveComma(domains, [&](Attribute attr) {
1828 ports[cast<IntegerAttr>(attr).getUInt()].name.getValue());
1833 auto kind = cast<FlatSymbolRefAttr>(attr);
1840void Emitter::emitLocation(Location loc) {
1842 ps << PP::neverbreak;
1844 dyn_cast_or_null<FileLineColLoc, LocationAttr>(LocationAttr(loc))) {
1845 ps <<
" @[" << fileLoc.getFilename().getValue();
1846 if (
auto line = fileLoc.getLine()) {
1849 if (
auto col = fileLoc.getColumn()) {
1866 std::optional<size_t> targetLineLength,
1868 Emitter emitter(os, version,
1869 targetLineLength.value_or(defaultTargetLineLength));
1870 for (
auto &op : *
module.getBody()) {
1871 if (auto circuitOp = dyn_cast<CircuitOp>(op))
1872 emitter.emitCircuit(circuitOp);
1874 return emitter.finalize();
1879 "target-line-length",
1880 llvm::cl::desc(
"Target line length for emitted .fir"),
1881 llvm::cl::value_desc(
"number of chars"),
1882 llvm::cl::init(defaultTargetLineLength));
1883 static mlir::TranslateFromMLIRRegistration toFIR(
1884 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
1885 [](ModuleOp module, llvm::raw_ostream &os) {
1888 [](mlir::DialectRegistry ®istry) {
1889 registry.insert<chirrtl::CHIRRTLDialect>();
1890 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.