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(AsResetPrimOp,
"asReset");
192 HANDLE(AsClockPrimOp,
"asClock");
196 HANDLE(AndRPrimOp,
"andr");
198 HANDLE(XorRPrimOp,
"xorr");
202 void emitAttribute(MemDirAttr attr);
203 void emitAttribute(RUWBehaviorAttr attr);
206 void emitType(Type type,
bool includeConst =
true);
207 void emitTypeWithColon(Type type) {
208 ps << PP::space <<
":" << PP::nbsp;
213 void emitDomains(Attribute attr, ArrayRef<PortInfo> ports);
216 void emitLocation(Location loc);
217 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
218 template <
typename... Args>
219 void emitLocationAndNewLine(Args... args) {
222 ps << PP::neverbreak;
223 emitLocation(args...);
227 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
228 llvm::function_ref<
void()> emitRHS,
230 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
232 ps.scopedBox(PP::ibox2, [&]() {
234 ps << *wordBeforeLHS << PP::space;
238 ps << PP::space << syntax << PP::nbsp;
240 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
245 void emitSubExprIBox2(Value v) {
246 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
251 template <
typename Container,
typename EachFn>
252 void interleaveComma(
const Container &c, EachFn eachFn) {
253 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
258 void interleaveComma(ValueRange ops) {
259 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
262 void emitStatementFunctionOp(
PPExtString name, Operation *op) {
265 ps.scopedBox(PP::ibox0, [&]() {
266 interleaveComma(op->getOperands());
269 emitLocationAndNewLine(op);
272 template <
typename EachFn,
typename Range>
273 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
276 ps.scopedBox(PP::ibox0, [&]() {
277 interleaveComma(r, eachFn);
282 void emitLiteralExpression(Type type, ValueRange values) {
283 return emitLiteralExpression(type, values,
284 [&](Value v) { emitSubExprIBox2(v); });
288 void emitSymbol(SymbolRefAttr symbol) {
289 ps.ibox(2, IndentStyle::Block);
290 ps << symbol.getRootReference();
291 for (
auto nested : symbol.getNestedReferences()) {
294 ps << nested.getAttr();
301 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
302 encounteredError =
true;
303 return op->emitError(message);
307 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
308 encounteredError =
true;
309 return op->emitOpError(message);
314 std::optional<StringRef> lookupEmittedName(Value value) {
315 auto it = valueNames.find(value);
316 if (it != valueNames.end())
323 void emitPendingNewlineIfNeeded() {
324 if (pendingNewline) {
325 pendingNewline =
false;
329 void setPendingNewline() {
331 pendingNewline =
true;
334 void startStatement() { emitPendingNewlineIfNeeded(); }
352 bool pendingNewline =
false;
355 bool encounteredError =
false;
360 DenseMap<Value, StringRef> valueNames;
361 StringSet<> valueNamesStorage;
365 StringAttr legalize(StringAttr attr) {
366 StringRef str = attr.getValue();
367 if (str.empty() || !
isdigit(str.front()))
369 return StringAttr::get(attr.getContext(),
"`" + Twine(attr) +
"`");
372 void addValueName(Value value, StringAttr attr) {
373 valueNames.insert({value, attr.getValue()});
375 void addValueName(Value value, StringRef str) {
376 auto it = valueNamesStorage.insert(str);
377 valueNames.insert({value, it.first->getKey()});
379 void addForceable(Forceable op, StringAttr attr) {
380 addValueName(op.getData(), attr);
381 if (op.isForceable()) {
382 SmallString<32> rwName;
383 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
384 addValueName(op.getDataRef(), rwName);
393 SymbolTable symbolTable;
396 SymInfos(Operation *op) : symbolTable(op), istc(op) {}
398 std::optional<std::reference_wrapper<SymInfos>> symInfos;
405LogicalResult Emitter::finalize() {
return failure(encounteredError); }
408void Emitter::emitCircuit(CircuitOp op) {
409 circuitNamespace.add(op);
410 SymInfos circuitSymInfos(op);
411 symInfos = circuitSymInfos;
413 ps <<
"FIRRTL version ";
420 ps <<
"circuit " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
424 if (encounteredError)
426 TypeSwitch<Operation *>(&bodyOp)
427 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](
auto op) {
431 .Case<DomainOp, LayerOp, OptionOp, FormalOp, SimulationOp>(
432 [&](
auto op) { emitDeclaration(op); })
433 .Default([&](
auto op) {
434 emitOpError(op,
"not supported for emission inside circuit");
438 circuitNamespace.clear();
439 symInfos = std::nullopt;
442void Emitter::emitEnabledLayers(ArrayRef<Attribute> layers) {
443 for (
auto layer : layers) {
445 ps.
cbox(2, IndentStyle::Block);
446 ps <<
"enablelayer" << PP::space;
447 emitSymbol(cast<SymbolRefAttr>(layer));
452void Emitter::emitKnownLayers(ArrayRef<Attribute> layers) {
453 for (
auto layer : layers) {
455 ps.
cbox(2, IndentStyle::Block);
456 ps <<
"knownlayer" << PP::space;
457 emitSymbol(cast<SymbolRefAttr>(layer));
462void Emitter::emitRequirements(ArrayRef<Attribute> requirements) {
463 if (requirements.empty())
466 ps.
cbox(2, IndentStyle::Block);
467 ps <<
"requires" << PP::space;
468 llvm::interleaveComma(requirements, ps, [&](Attribute req) {
474void Emitter::emitParamAssign(ParamDeclAttr param, Operation *op,
475 std::optional<PPExtString> wordBeforeLHS) {
477 ps << *wordBeforeLHS << PP::nbsp;
479 ps <<
PPExtString(param.getName().strref()) << PP::nbsp <<
"=" << PP::nbsp;
480 emitParamValue(param.getValue(), op);
483void Emitter::emitParamValue(Attribute value, Operation *op) {
484 TypeSwitch<Attribute>(value)
485 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
486 .Case<FloatAttr>([&](
auto attr) {
488 attr.getValue().toString(str);
493 .Case<ArrayAttr>([&](
auto attr) {
496 interleaveComma(attr.getValue(),
497 [&](
auto element) { emitParamValue(element, op); });
501 .Case<DictionaryAttr>([&](
auto attr) {
504 interleaveComma(attr.getValue(), [&](
auto field) {
505 ps << PPExtString(field.getName()) << PP::nbsp <<
"=" << PP::nbsp;
506 emitParamValue(field.getValue(), op);
511 .Default([&](
auto attr) {
512 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
513 ps <<
"<unsupported-attr ";
519void Emitter::emitGenericIntrinsic(GenericIntrinsicOp op) {
523 ps << op.getIntrinsic();
525 auto params = op.getParameters();
526 if (!params.empty()) {
528 ps.scopedBox(PP::ibox0, [&]() {
530 params.getAsRange<ParamDeclAttr>(),
531 [&](ParamDeclAttr param) { emitParamAssign(param, op); });
536 if (op.getNumResults() != 0)
537 emitTypeWithColon(op.getResult().getType());
539 if (op.getNumOperands() != 0) {
540 ps <<
"," << PP::space;
541 ps.
scopedBox(PP::ibox0, [&]() { interleaveComma(op->getOperands()); });
548void Emitter::emitModule(FModuleOp op) {
550 ps.
cbox(4, IndentStyle::Block);
552 ps <<
"public" << PP::nbsp;
553 ps <<
"module " <<
PPExtString(legalize(op.getNameAttr()));
554 emitEnabledLayers(op.getLayers());
555 ps << PP::nbsp <<
":" << PP::end;
562 auto ports = op.getPorts();
563 emitModulePorts(ports, op.getArguments());
564 if (!ports.empty() && !op.getBodyBlock()->empty())
568 emitStatementsInBlock(*op.getBodyBlock());
571 valueNamesStorage.clear();
575void Emitter::emitModule(FExtModuleOp op) {
577 ps.
cbox(4, IndentStyle::Block);
578 ps <<
"extmodule " <<
PPExtString(legalize(op.getNameAttr()));
579 emitKnownLayers(op.getKnownLayers());
580 emitEnabledLayers(op.getLayers());
581 if (
auto reqs = op.getExternalRequirements())
582 emitRequirements(reqs.getValue());
583 ps << PP::nbsp <<
":" << PP::end;
590 auto ports = op.getPorts();
591 emitModulePorts(ports);
594 if (op.getDefname() && !op.getDefname()->empty()) {
596 ps <<
"defname = " <<
PPExtString(*op.getDefname());
601 emitModuleParameters(op, op.getParameters());
606void Emitter::emitModule(FIntModuleOp op) {
608 ps.
cbox(4, IndentStyle::Block);
609 ps <<
"intmodule " <<
PPExtString(legalize(op.getNameAttr()));
610 emitEnabledLayers(op.getLayers());
611 ps << PP::nbsp <<
":" << PP::end;
618 auto ports = op.getPorts();
619 emitModulePorts(ports);
622 ps <<
"intrinsic = " <<
PPExtString(op.getIntrinsic());
626 emitModuleParameters(op, op.getParameters());
633void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
634 Block::BlockArgListType arguments) {
636 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
638 const auto &port = ports[i];
639 ps << (port.direction == Direction::In ?
"input " :
"output ");
640 auto legalName = legalize(port.name);
641 if (!arguments.empty())
642 addValueName(arguments[i], legalName);
645 emitDomains(port.domains, ports);
646 emitLocation(ports[i].loc);
651void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
652 for (
auto param : parameters.getAsRange<ParamDeclAttr>()) {
654 emitParamAssign(param, op,
PPExtString(
"parameter"));
659void Emitter::emitDeclaration(DomainOp op) {
661 ps <<
"domain " <<
PPExtString(op.getSymName()) <<
" :";
662 emitLocationAndNewLine(op);
664 for (
auto attr : op.getFields()) {
665 auto fieldAttr = cast<DomainFieldAttr>(attr);
666 ps << PP::newline <<
PPExtString(fieldAttr.getName()) <<
" : ";
667 emitType(fieldAttr.getType());
673void Emitter::emitDeclaration(LayerOp op) {
675 ps <<
"layer " <<
PPExtString(op.getSymName()) <<
", "
676 <<
PPExtString(stringifyLayerConvention(op.getConvention()));
678 if (
auto outputFile = op->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
684 emitLocationAndNewLine(op);
686 for (
auto &bodyOp : op.getBody().getOps()) {
687 TypeSwitch<Operation *>(&bodyOp)
688 .Case<LayerOp>([&](
auto op) { emitDeclaration(op); })
689 .Default([&](
auto op) {
691 "not supported for emission inside layer definition");
698void Emitter::emitDeclaration(OptionOp op) {
700 ps <<
"option " <<
PPExtString(legalize(op.getSymNameAttr())) <<
" :";
703 for (
auto caseOp : op.getBody().getOps<OptionCaseOp>()) {
705 ps <<
PPExtString(legalize(caseOp.getSymNameAttr()));
706 emitLocation(caseOp);
709 ps << PP::newline << PP::newline;
713void Emitter::emitDeclaration(FormalOp op) {
714 emitFormalLike(op,
"formal", op.getSymNameAttr(),
715 op.getModuleNameAttr().getAttr(), op.getParameters());
719void Emitter::emitDeclaration(SimulationOp op) {
720 emitFormalLike(op,
"simulation", op.getSymNameAttr(),
721 op.getModuleNameAttr().getAttr(), op.getParameters());
725void Emitter::emitFormalLike(Operation *op, StringRef keyword,
726 StringAttr symName, StringAttr moduleName,
727 DictionaryAttr params) {
729 ps.
cbox(4, IndentStyle::Block);
730 ps << keyword <<
" " <<
PPExtString(legalize(symName));
732 ps << PP::nbsp <<
":" << PP::end;
737 for (
auto param : params) {
739 ps <<
PPExtString(param.getName()) << PP::nbsp <<
"=" << PP::nbsp;
740 emitParamValue(param.getValue(), op);
754 return (
isExpression(op) && !isa<InvalidValueOp>(op)) ||
755 (isa<GenericIntrinsicOp>(op) && op->hasOneUse() &&
759void Emitter::emitStatementsInBlock(Block &block) {
760 for (
auto &bodyOp : block) {
761 if (encounteredError)
765 TypeSwitch<Operation *>(&bodyOp)
766 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
767 PrintFOp, FPrintFOp, FFlushOp, AssertOp, AssumeOp, CoverOp,
768 ConnectOp, MatchingConnectOp, PropAssignOp, InstanceOp,
769 InstanceChoiceOp, AttachOp, MemOp, InvalidValueOp, SeqMemOp,
770 CombMemOp, MemoryPortOp, MemoryDebugPortOp, MemoryPortAccessOp,
771 DomainDefineOp, RefDefineOp, RefForceOp, RefForceInitialOp,
772 RefReleaseOp, RefReleaseInitialOp, LayerBlockOp,
773 GenericIntrinsicOp, DomainCreateAnonOp>(
774 [&](
auto op) { emitStatement(op); })
775 .Default([&](
auto op) {
777 ps <<
"// operation " <<
PPExtString(op->getName().getStringRef());
779 emitOpError(op,
"not supported as statement");
784void Emitter::emitStatement(WhenOp op) {
787 emitExpression(op.getCondition());
789 emitLocationAndNewLine(op);
790 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
792 if (!op.hasElseRegion())
799 auto &elseBlock = op.getElseBlock();
800 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
801 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
802 emitStatement(whenOp);
809 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
812void Emitter::emitStatement(WireOp op) {
813 auto legalName = legalize(op.getNameAttr());
814 addForceable(op, legalName);
818 emitTypeWithColon(op.getResult().getType());
820 emitLocationAndNewLine(op);
823void Emitter::emitStatement(RegOp op) {
824 auto legalName = legalize(op.getNameAttr());
825 addForceable(op, legalName);
829 emitTypeWithColon(op.getResult().getType());
830 ps <<
"," << PP::space;
831 emitExpression(op.getClockVal());
833 emitLocationAndNewLine(op);
836void Emitter::emitStatement(RegResetOp op) {
837 auto legalName = legalize(op.getNameAttr());
838 addForceable(op, legalName);
842 ps <<
"regreset " << legalName;
843 emitTypeWithColon(op.getResult().getType());
844 ps <<
"," << PP::space;
845 emitExpression(op.getClockVal());
846 ps <<
"," << PP::space;
847 emitExpression(op.getResetSignal());
848 ps <<
"," << PP::space;
849 emitExpression(op.getResetValue());
853 ps <<
"reg " << legalName;
854 emitTypeWithColon(op.getResult().getType());
855 ps <<
"," << PP::space;
856 emitExpression(op.getClockVal());
857 ps << PP::space <<
"with :";
859 ps << PP::neverbreak;
862 ps <<
"reset => (" << PP::ibox0;
863 emitExpression(op.getResetSignal());
864 ps <<
"," << PP::space;
865 emitExpression(op.getResetValue());
866 ps <<
")" << PP::end;
869 emitLocationAndNewLine(op);
872void Emitter::emitStatement(NodeOp op) {
873 auto legalName = legalize(op.getNameAttr());
874 addForceable(op, legalName);
876 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(legalName); },
877 [&]() { emitExpression(op.getInput()); });
878 emitLocationAndNewLine(op);
881void Emitter::emitStatement(StopOp op) {
884 ps <<
"stop(" << PP::ibox0;
885 emitExpression(op.getClock());
886 ps <<
"," << PP::space;
887 emitExpression(op.getCond());
888 ps <<
"," << PP::space;
890 ps <<
")" << PP::end;
891 if (!op.getName().empty()) {
892 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
895 emitLocationAndNewLine(op);
898void Emitter::emitStatement(SkipOp op) {
901 emitLocationAndNewLine(op);
904void Emitter::emitFormatString(Operation *op, StringRef origFormatString,
905 OperandRange substitutionOperands,
906 llvm::SmallVectorImpl<Value> &substitutions) {
915 SmallString<64> formatString;
916 for (
size_t i = 0, e = origFormatString.size(), opIdx = 0; i != e; ++i) {
917 auto c = origFormatString[i];
920 formatString.push_back(c);
923 SmallString<6> width;
924 c = origFormatString[++i];
927 c = origFormatString[++i];
936 formatString.append(width);
939 substitutions.push_back(substitutionOperands[opIdx++]);
942 formatString.push_back(c);
947 if (origFormatString.slice(i, i + 4) ==
"{{}}") {
948 formatString.append(
"{{");
949 TypeSwitch<Operation *>(substitutionOperands[opIdx++].getDefiningOp())
951 [&](
auto time) { formatString.append(
"SimulationTime"); })
952 .Case<HierarchicalModuleNameOp>([&](
auto time) {
953 formatString.append(
"HierarchicalModuleName");
956 emitError(op,
"unsupported fstring substitution type");
958 formatString.append(
"}}");
963 formatString.push_back(c);
969void Emitter::emitStatement(PrintFOp op) {
972 ps <<
"printf(" << PP::ibox0;
973 emitExpression(op.getClock());
974 ps <<
"," << PP::space;
975 emitExpression(op.getCond());
976 ps <<
"," << PP::space;
978 SmallVector<Value, 4> substitutions;
979 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
981 for (
auto operand : substitutions) {
982 ps <<
"," << PP::space;
983 emitExpression(operand);
985 ps <<
")" << PP::end;
986 if (!op.getName().empty()) {
987 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
990 emitLocationAndNewLine(op);
993void Emitter::emitStatement(FPrintFOp op) {
996 ps <<
"fprintf(" << PP::ibox0;
997 emitExpression(op.getClock());
998 ps <<
"," << PP::space;
999 emitExpression(op.getCond());
1000 ps <<
"," << PP::space;
1002 SmallVector<Value, 4> outputFileSubstitutions;
1003 emitFormatString(op, op.getOutputFile(), op.getOutputFileSubstitutions(),
1004 outputFileSubstitutions);
1005 if (!outputFileSubstitutions.empty()) {
1006 ps <<
"," << PP::space;
1007 interleaveComma(outputFileSubstitutions);
1010 ps <<
"," << PP::space;
1011 SmallVector<Value, 4> substitutions;
1012 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
1014 if (!substitutions.empty()) {
1015 ps <<
"," << PP::space;
1016 interleaveComma(substitutions);
1019 ps <<
")" << PP::end;
1020 if (!op.getName().empty()) {
1021 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1024 emitLocationAndNewLine(op);
1027void Emitter::emitStatement(FFlushOp op) {
1030 ps <<
"fflush(" << PP::ibox0;
1031 emitExpression(op.getClock());
1032 ps <<
"," << PP::space;
1033 emitExpression(op.getCond());
1034 if (op.getOutputFileAttr()) {
1035 ps <<
"," << PP::space;
1036 SmallVector<Value, 4> substitutions;
1037 emitFormatString(op, op.getOutputFileAttr(),
1038 op.getOutputFileSubstitutions(), substitutions);
1039 if (!substitutions.empty()) {
1040 ps <<
"," << PP::space;
1041 interleaveComma(substitutions);
1044 ps <<
")" << PP::end;
1046 emitLocationAndNewLine(op);
1050void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
1053 ps << mnemonic <<
"(" << PP::ibox0;
1054 emitExpression(op.getClock());
1055 ps <<
"," << PP::space;
1056 emitExpression(op.getPredicate());
1057 ps <<
"," << PP::space;
1058 emitExpression(op.getEnable());
1059 ps <<
"," << PP::space;
1061 ps <<
")" << PP::end;
1062 if (!op.getName().empty()) {
1063 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1066 emitLocationAndNewLine(op);
1069void Emitter::emitStatement(ConnectOp op) {
1073 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1074 ps <<
"invalidate" << PP::space;
1075 emitExpression(op.getDest());
1077 ps <<
"connect" << PP::space;
1078 emitExpression(op.getDest());
1079 ps <<
"," << PP::space;
1080 emitExpression(op.getSrc());
1084 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1085 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1087 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1090 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1093 emitLocationAndNewLine(op);
1096void Emitter::emitStatement(MatchingConnectOp op) {
1100 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1101 ps <<
"invalidate" << PP::space;
1102 emitExpression(op.getDest());
1104 ps <<
"connect" << PP::space;
1105 emitExpression(op.getDest());
1106 ps <<
"," << PP::space;
1107 emitExpression(op.getSrc());
1111 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1112 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1114 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1117 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1120 emitLocationAndNewLine(op);
1123void Emitter::emitStatement(PropAssignOp op) {
1126 ps <<
"propassign" << PP::space;
1127 interleaveComma(op.getOperands());
1129 emitLocationAndNewLine(op);
1132void Emitter::emitStatement(InstanceOp op) {
1134 auto legalName = legalize(op.getNameAttr());
1136 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
1137 emitLocationAndNewLine(op);
1141 SmallString<16> portName(legalName);
1142 portName.push_back(
'.');
1143 unsigned baseLen = portName.size();
1144 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1145 portName.append(legalize(op.getPortNameAttr(i)));
1146 addValueName(op.getResult(i), portName);
1147 portName.resize(baseLen);
1151void Emitter::emitStatement(InstanceChoiceOp op) {
1153 auto legalName = legalize(op.getNameAttr());
1154 ps <<
"instchoice " <<
PPExtString(legalName) <<
" of "
1155 <<
PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
1156 <<
PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
1159 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
1161 ps <<
PPExtString(legalize(optSym.getLeafReference()));
1166 setPendingNewline();
1168 SmallString<16> portName(legalName);
1169 portName.push_back(
'.');
1170 unsigned baseLen = portName.size();
1171 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1172 portName.append(legalize(op.getPortNameAttr(i)));
1173 addValueName(op.getResult(i), portName);
1174 portName.resize(baseLen);
1178void Emitter::emitStatement(AttachOp op) {
1179 emitStatementFunctionOp(
PPExtString(
"attach"), op);
1182void Emitter::emitStatement(MemOp op) {
1183 auto legalName = legalize(op.getNameAttr());
1184 SmallString<16> portName(legalName);
1185 portName.push_back(
'.');
1186 auto portNameBaseLen = portName.size();
1187 for (
auto result :
llvm::zip(op.getResults(), op.getPortNames())) {
1188 portName.resize(portNameBaseLen);
1189 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
1190 addValueName(std::get<0>(result), portName);
1195 emitLocationAndNewLine(op);
1198 ps <<
"data-type => ";
1199 emitType(op.getDataType());
1204 ps <<
"read-latency => ";
1207 ps <<
"write-latency => ";
1211 SmallString<16> reader, writer, readwriter;
1212 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
1213 auto add = [&](SmallString<16> &to, StringAttr name) {
1216 to.append(name.getValue());
1218 switch (port.second) {
1219 case MemOp::PortKind::Read:
1220 add(reader, legalize(port.first));
1222 case MemOp::PortKind::Write:
1223 add(writer, legalize(port.first));
1225 case MemOp::PortKind::ReadWrite:
1226 add(readwriter, legalize(port.first));
1228 case MemOp::PortKind::Debug:
1229 emitOpError(op,
"has unsupported 'debug' port");
1233 if (!reader.empty())
1234 ps <<
"reader => " << reader << PP::newline;
1235 if (!writer.empty())
1236 ps <<
"writer => " << writer << PP::newline;
1237 if (!readwriter.empty())
1238 ps <<
"readwriter => " << readwriter << PP::newline;
1240 ps <<
"read-under-write => ";
1241 emitAttribute(op.getRuwAttr());
1242 setPendingNewline();
1246void Emitter::emitStatement(SeqMemOp op) {
1249 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
1250 emitTypeWithColon(op.getType());
1251 ps <<
"," << PP::space;
1252 emitAttribute(op.getRuwAttr());
1254 emitLocationAndNewLine(op);
1257void Emitter::emitStatement(CombMemOp op) {
1260 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
1261 emitTypeWithColon(op.getType());
1263 emitLocationAndNewLine(op);
1266void Emitter::emitStatement(MemoryPortOp op) {
1268 addValueName(op.getData(), legalize(op.getNameAttr()));
1271void Emitter::emitStatement(MemoryDebugPortOp op) {
1273 addValueName(op.getData(), legalize(op.getNameAttr()));
1276void Emitter::emitStatement(MemoryPortAccessOp op) {
1280 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1281 emitAttribute(port.getDirection());
1283 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
1286 auto *mem = port.getMemory().getDefiningOp();
1287 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1288 ps << legalize(seqMem.getNameAttr());
1290 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1294 emitExpression(op.getIndex());
1298 emitExpression(op.getClock());
1300 emitLocationAndNewLine(op);
1303void Emitter::emitStatement(DomainDefineOp op) {
1305 if (isa_and_nonnull<DomainCreateAnonOp>(op.getSrc().getDefiningOp()))
1309 emitAssignLike([&]() { emitExpression(op.getDest()); },
1310 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1312 emitLocationAndNewLine(op);
1315void Emitter::emitStatement(RefDefineOp op) {
1317 emitAssignLike([&]() { emitExpression(op.getDest()); },
1318 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1320 emitLocationAndNewLine(op);
1323void Emitter::emitStatement(RefForceOp op) {
1324 emitStatementFunctionOp(
PPExtString(
"force"), op);
1327void Emitter::emitStatement(RefForceInitialOp op) {
1329 auto constantPredicate =
1330 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1331 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1334 emitExpression(op.getPredicate());
1335 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1337 ps <<
"force_initial(";
1339 interleaveComma({op.getDest(), op.getSrc()});
1344 emitLocationAndNewLine(op);
1347void Emitter::emitStatement(RefReleaseOp op) {
1348 emitStatementFunctionOp(
PPExtString(
"release"), op);
1351void Emitter::emitStatement(RefReleaseInitialOp op) {
1353 auto constantPredicate =
1354 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1355 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1358 emitExpression(op.getPredicate());
1359 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1361 ps <<
"release_initial(";
1362 emitExpression(op.getDest());
1366 emitLocationAndNewLine(op);
1369void Emitter::emitStatement(LayerBlockOp op) {
1371 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1372 emitLocationAndNewLine(op);
1373 auto *body = op.getBody();
1374 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1377void Emitter::emitStatement(InvalidValueOp op) {
1380 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1381 return use.getOperandNumber() == 1 &&
1382 isa<ConnectOp, MatchingConnectOp>(use.getOwner());
1388 auto name = circuitNamespace.newName(
"_invalid");
1389 addValueName(op, name);
1391 emitType(op.getType());
1392 emitLocationAndNewLine(op);
1398 emitLocationAndNewLine(op);
1401void Emitter::emitStatement(GenericIntrinsicOp op) {
1404 emitGenericIntrinsic(op);
1407 auto name = circuitNamespace.newName(
"_gen_int");
1408 addValueName(op.getResult(), name);
1409 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(name); },
1410 [&]() { emitGenericIntrinsic(op); });
1412 emitLocationAndNewLine(op);
1415void Emitter::emitStatement(DomainCreateAnonOp op) {
1419void Emitter::emitExpression(Value value) {
1422 if (
auto name = lookupEmittedName(value)) {
1428 auto op = value.getDefiningOp();
1429 assert(op &&
"value must either be a block arg or the result of an op");
1430 TypeSwitch<Operation *>(op)
1433 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1434 OpenSubfieldOp, OpenSubindexOp,
1436 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1437 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1438 EQPrimOp, NEQPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1440 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsResetPrimOp,
1441 AsClockPrimOp, CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp,
1444 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1445 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1446 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1447 UnresolvedPathOp, GenericIntrinsicOp, CatPrimOp, UnsafeDomainCastOp,
1450 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp,
1452 TimeOp>([&](
auto op) {
1453 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1455 .Default([&](
auto op) {
1456 emitOpError(op,
"not supported as expression");
1457 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1462void Emitter::emitExpression(ConstantOp op) {
1464 emitType(op.getType(),
false);
1471void Emitter::emitExpression(SpecialConstantOp op) {
1472 auto emitInner = [&]() {
1479 .
Case<ClockType>([&](
auto type) {
1484 .Case<ResetType>([&](
auto type) { emitInner(); })
1485 .Case<AsyncResetType>([&](
auto type) {
1486 ps <<
"asAsyncReset(";
1493void Emitter::emitExpression(SubfieldOp op) {
1494 BundleType type = op.getInput().getType();
1495 emitExpression(op.getInput());
1496 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1500void Emitter::emitExpression(SubindexOp op) {
1501 emitExpression(op.getInput());
1508void Emitter::emitExpression(SubaccessOp op) {
1509 emitExpression(op.getInput());
1511 emitExpression(op.getIndex());
1515void Emitter::emitExpression(OpenSubfieldOp op) {
1516 auto type = op.getInput().getType();
1517 emitExpression(op.getInput());
1518 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1521void Emitter::emitExpression(OpenSubindexOp op) {
1522 emitExpression(op.getInput());
1528void Emitter::emitExpression(RefSendOp op) {
1530 emitExpression(op.getBase());
1534void Emitter::emitExpression(RefResolveOp op) {
1536 emitExpression(op.getRef());
1540void Emitter::emitExpression(RefSubOp op) {
1541 emitExpression(op.getInput());
1543 .
Case<FVectorType>([&](
auto type) {
1549 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1552void Emitter::emitExpression(RWProbeOp op) {
1556 auto target = symInfos->get().irn.lookup(op.getTarget());
1558 if (target.isPort()) {
1559 auto mod = cast<FModuleOp>(target.getOp());
1560 auto port = target.getPort();
1561 base = mod.getArgument(port);
1563 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1566 emitExpression(base);
1569 auto fieldID = target.getField();
1570 auto type = base.getType();
1573 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1574 auto index = vecTy.getIndexForFieldID(fieldID);
1578 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1580 fieldID = subfieldID;
1582 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1583 auto index = bundleTy.getIndexForFieldID(fieldID);
1584 ps <<
"." << bundleTy.getElementName(index);
1585 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1587 fieldID = subfieldID;
1593void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1595void Emitter::emitExpression(UninferredResetCastOp op) {
1596 emitExpression(op.getInput());
1599void Emitter::emitExpression(FIntegerConstantOp op) {
1605void Emitter::emitExpression(BoolConstantOp op) {
1606 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1609void Emitter::emitExpression(DoubleConstantOp op) {
1615 SmallString<16> str;
1616 op.getValueAttr().getValue().toString(str);
1621void Emitter::emitExpression(StringConstantOp op) {
1627void Emitter::emitExpression(ListCreateOp op) {
1628 return emitLiteralExpression(op.getType(), op.getElements());
1631void Emitter::emitExpression(UnresolvedPathOp op) {
1637void Emitter::emitExpression(GenericIntrinsicOp op) {
1638 emitGenericIntrinsic(op);
1641void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1643void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1644 ArrayRef<uint32_t> attrs) {
1645 ps << mnemonic <<
"(" << PP::ibox0;
1646 interleaveComma(op->getOperands());
1647 if (!op->getOperands().empty() && !attrs.empty())
1648 ps <<
"," << PP::space;
1649 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1650 ps <<
")" << PP::end;
1653void Emitter::emitExpression(CatPrimOp op) {
1654 size_t numOperands = op.getNumOperands();
1655 switch (numOperands) {
1658 emitType(op.getType(),
false);
1662 auto operand = op->getOperand(0);
1664 if (isa<UIntType>(operand.getType()))
1665 return emitExpression(operand);
1668 ps <<
"cat(" << PP::ibox0;
1669 emitExpression(op->getOperand(0));
1670 ps <<
"," << PP::space <<
"SInt<0>(0))" << PP::end;
1676 for (
size_t i = 0; i < numOperands - 1; ++i) {
1677 ps <<
"cat(" << PP::ibox0;
1678 emitExpression(op->getOperand(i));
1679 ps <<
"," << PP::space;
1682 emitExpression(op->getOperand(numOperands - 1));
1683 for (
size_t i = 0; i < numOperands - 1; ++i)
1684 ps <<
")" << PP::end;
1689void Emitter::emitExpression(UnsafeDomainCastOp op) {
1690 ps <<
"unsafe_domain_cast(" << PP::ibox0;
1691 interleaveComma(op.getOperands(),
1692 [&](Value operand) { emitExpression(operand); });
1693 ps <<
")" << PP::end;
1696void Emitter::emitExpression(UnknownValueOp op) {
1698 emitTypeWithColon(op.getType());
1701void Emitter::emitAttribute(MemDirAttr attr) {
1703 case MemDirAttr::Infer:
1706 case MemDirAttr::Read:
1709 case MemDirAttr::Write:
1712 case MemDirAttr::ReadWrite:
1718void Emitter::emitAttribute(RUWBehaviorAttr attr) {
1719 switch (attr.getValue()) {
1720 case RUWBehavior::Undefined:
1723 case RUWBehavior::Old:
1726 case RUWBehavior::New:
1733void Emitter::emitType(Type type,
bool includeConst) {
1734 if (includeConst &&
isConst(type))
1736 auto emitWidth = [&](std::optional<int32_t> width) {
1745 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1746 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1747 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1748 .Case<UIntType>([&](
auto type) {
1750 emitWidth(type.getWidth());
1752 .Case<SIntType>([&](
auto type) {
1754 emitWidth(type.getWidth());
1756 .Case<AnalogType>([&](
auto type) {
1758 emitWidth(type.getWidth());
1760 .Case<OpenBundleType, BundleType>([&](
auto type) {
1762 if (!type.getElements().empty())
1764 bool anyEmitted =
false;
1766 for (
auto &element : type.getElements()) {
1768 ps <<
"," << PP::space;
1772 ps << legalize(element.name);
1773 emitTypeWithColon(element.type);
1782 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1783 emitType(type.getElementType());
1788 .Case<RefType>([&](RefType type) {
1789 if (type.getForceable())
1792 ps.
cbox(2, IndentStyle::Block);
1794 emitType(type.getType());
1795 if (
auto layer = type.getLayer()) {
1798 emitSymbol(type.getLayer());
1803 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1804 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1805 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1806 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1807 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1808 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1809 .Case<ListType>([&](ListType type) {
1811 emitType(type.getElementType());
1814 .Case<DomainType>([&](DomainType type) { ps <<
"Domain"; })
1815 .Default([&](
auto type) {
1816 llvm_unreachable(
"all types should be implemented");
1820void Emitter::emitDomains(Attribute attr, ArrayRef<PortInfo> ports) {
1823 if (
auto domains = dyn_cast<ArrayAttr>(attr)) {
1824 if (domains.empty())
1828 interleaveComma(domains, [&](Attribute attr) {
1830 ports[cast<IntegerAttr>(attr).getUInt()].name.getValue());
1835 auto kind = cast<FlatSymbolRefAttr>(attr);
1842void Emitter::emitLocation(Location loc) {
1844 ps << PP::neverbreak;
1846 dyn_cast_or_null<FileLineColLoc, LocationAttr>(LocationAttr(loc))) {
1847 ps <<
" @[" << fileLoc.getFilename().getValue();
1848 if (
auto line = fileLoc.getLine()) {
1851 if (
auto col = fileLoc.getColumn()) {
1868 std::optional<size_t> targetLineLength,
1870 Emitter emitter(os, version,
1871 targetLineLength.value_or(defaultTargetLineLength));
1872 for (
auto &op : *
module.getBody()) {
1873 if (auto circuitOp = dyn_cast<CircuitOp>(op))
1874 emitter.emitCircuit(circuitOp);
1876 return emitter.finalize();
1881 "target-line-length",
1882 llvm::cl::desc(
"Target line length for emitted .fir"),
1883 llvm::cl::value_desc(
"number of chars"),
1884 llvm::cl::init(defaultTargetLineLength));
1885 static mlir::TranslateFromMLIRRegistration toFIR(
1886 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
1887 [](ModuleOp module, llvm::raw_ostream &os) {
1890 [](mlir::DialectRegistry ®istry) {
1891 registry.insert<chirrtl::CHIRRTLDialect>();
1892 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.