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);
115 void emitStatement(DomainCreateOp op);
118 void emitVerifStatement(T op, StringRef mnemonic);
119 void emitStatement(AssertOp op) { emitVerifStatement(op,
"assert"); }
120 void emitStatement(AssumeOp op) { emitVerifStatement(op,
"assume"); }
121 void emitStatement(CoverOp op) { emitVerifStatement(op,
"cover"); }
124 void emitExpression(Value value);
125 void emitExpression(ConstantOp op);
126 void emitExpression(SpecialConstantOp op);
127 void emitExpression(SubfieldOp op);
128 void emitExpression(SubindexOp op);
129 void emitExpression(SubaccessOp op);
130 void emitExpression(OpenSubfieldOp op);
131 void emitExpression(DomainSubfieldOp op);
132 void emitExpression(OpenSubindexOp op);
133 void emitExpression(RefResolveOp op);
134 void emitExpression(RefSendOp op);
135 void emitExpression(RefSubOp op);
136 void emitExpression(RWProbeOp op);
137 void emitExpression(RefCastOp op);
138 void emitExpression(UninferredResetCastOp op);
139 void emitExpression(ConstCastOp op);
140 void emitExpression(StringConstantOp op);
141 void emitExpression(FIntegerConstantOp op);
142 void emitExpression(BoolConstantOp op);
143 void emitExpression(DoubleConstantOp op);
144 void emitExpression(ListCreateOp op);
145 void emitExpression(UnresolvedPathOp op);
146 void emitExpression(GenericIntrinsicOp op);
147 void emitExpression(CatPrimOp op);
148 void emitExpression(UnsafeDomainCastOp op);
149 void emitExpression(UnknownValueOp op);
151 void emitPrimExpr(StringRef mnemonic, Operation *op,
152 ArrayRef<uint32_t> attrs = {});
154 void emitExpression(BitsPrimOp op) {
155 emitPrimExpr(
"bits", op, {op.getHi(), op.getLo()});
157 void emitExpression(HeadPrimOp op) {
158 emitPrimExpr(
"head", op, op.getAmount());
160 void emitExpression(TailPrimOp op) {
161 emitPrimExpr(
"tail", op, op.getAmount());
163 void emitExpression(PadPrimOp op) { emitPrimExpr(
"pad", op, op.getAmount()); }
164 void emitExpression(ShlPrimOp op) { emitPrimExpr(
"shl", op, op.getAmount()); }
165 void emitExpression(ShrPrimOp op) { emitPrimExpr(
"shr", op, op.getAmount()); }
167 void emitExpression(TimeOp op) {}
170#define HANDLE(OPTYPE, MNEMONIC) \
171 void emitExpression(OPTYPE op) { emitPrimExpr(MNEMONIC, op); }
186 HANDLE(DShlPrimOp,
"dshl");
187 HANDLE(DShlwPrimOp,
"dshlw");
188 HANDLE(DShrPrimOp,
"dshr");
190 HANDLE(AsSIntPrimOp,
"asSInt");
191 HANDLE(AsUIntPrimOp,
"asUInt");
192 HANDLE(AsAsyncResetPrimOp,
"asAsyncReset");
193 HANDLE(AsResetPrimOp,
"asReset");
194 HANDLE(AsClockPrimOp,
"asClock");
198 HANDLE(AndRPrimOp,
"andr");
200 HANDLE(XorRPrimOp,
"xorr");
201 HANDLE(StringConcatOp,
"string_concat");
205 void emitAttribute(MemDirAttr attr);
206 void emitAttribute(RUWBehaviorAttr attr);
209 void emitType(Type type,
bool includeConst =
true);
210 void emitTypeWithColon(Type type) {
211 ps << PP::space <<
":" << PP::nbsp;
216 void emitDomains(Attribute attr, ArrayRef<PortInfo> ports);
219 void emitLocation(Location loc);
220 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
221 template <
typename... Args>
222 void emitLocationAndNewLine(Args... args) {
225 ps << PP::neverbreak;
226 emitLocation(args...);
230 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
231 llvm::function_ref<
void()> emitRHS,
233 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
235 ps.scopedBox(PP::ibox2, [&]() {
237 ps << *wordBeforeLHS << PP::space;
241 ps << PP::space << syntax << PP::nbsp;
243 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
248 void emitSubExprIBox2(Value v) {
249 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
254 template <
typename Container,
typename EachFn>
255 void interleaveComma(
const Container &c, EachFn eachFn) {
256 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
261 void interleaveComma(ValueRange ops) {
262 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
265 void emitStatementFunctionOp(
PPExtString name, Operation *op) {
268 ps.scopedBox(PP::ibox0, [&]() {
269 interleaveComma(op->getOperands());
272 emitLocationAndNewLine(op);
275 template <
typename EachFn,
typename Range>
276 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
279 ps.scopedBox(PP::ibox0, [&]() {
280 interleaveComma(r, eachFn);
285 void emitLiteralExpression(Type type, ValueRange values) {
286 return emitLiteralExpression(type, values,
287 [&](Value v) { emitSubExprIBox2(v); });
291 void emitSymbol(SymbolRefAttr symbol) {
292 ps.ibox(2, IndentStyle::Block);
293 ps << symbol.getRootReference();
294 for (
auto nested : symbol.getNestedReferences()) {
297 ps << nested.getAttr();
304 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
305 encounteredError =
true;
306 return op->emitError(message);
310 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
311 encounteredError =
true;
312 return op->emitOpError(message);
317 std::optional<StringRef> lookupEmittedName(Value value) {
318 auto it = valueNames.find(value);
319 if (it != valueNames.end())
326 void emitPendingNewlineIfNeeded() {
327 if (pendingNewline) {
328 pendingNewline =
false;
332 void setPendingNewline() {
334 pendingNewline =
true;
337 void startStatement() { emitPendingNewlineIfNeeded(); }
355 bool pendingNewline =
false;
358 bool encounteredError =
false;
363 DenseMap<Value, StringRef> valueNames;
364 StringSet<> valueNamesStorage;
368 StringAttr legalize(StringAttr attr) {
369 StringRef str = attr.getValue();
370 if (str.empty() || !
isdigit(str.front()))
372 return StringAttr::get(attr.getContext(),
"`" + Twine(attr) +
"`");
375 void addValueName(Value value, StringAttr attr) {
376 valueNames.insert({value, attr.getValue()});
378 void addValueName(Value value, StringRef str) {
379 auto it = valueNamesStorage.insert(str);
380 valueNames.insert({value, it.first->getKey()});
382 void addForceable(Forceable op, StringAttr attr) {
383 addValueName(op.getData(), attr);
384 if (op.isForceable()) {
385 SmallString<32> rwName;
386 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
387 addValueName(op.getDataRef(), rwName);
396 SymbolTable symbolTable;
399 SymInfos(Operation *op) : symbolTable(op), istc(op) {}
401 std::optional<std::reference_wrapper<SymInfos>> symInfos;
408LogicalResult Emitter::finalize() {
return failure(encounteredError); }
411void Emitter::emitCircuit(CircuitOp op) {
412 circuitNamespace.add(op);
413 SymInfos circuitSymInfos(op);
414 symInfos = circuitSymInfos;
416 ps <<
"FIRRTL version ";
423 ps <<
"circuit " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
427 if (encounteredError)
429 TypeSwitch<Operation *>(&bodyOp)
430 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](
auto op) {
434 .Case<DomainOp, LayerOp, OptionOp, FormalOp, SimulationOp>(
435 [&](
auto op) { emitDeclaration(op); })
436 .Default([&](
auto op) {
437 emitOpError(op,
"not supported for emission inside circuit");
441 circuitNamespace.clear();
442 symInfos = std::nullopt;
445void Emitter::emitEnabledLayers(ArrayRef<Attribute> layers) {
446 for (
auto layer : layers) {
448 ps.
cbox(2, IndentStyle::Block);
449 ps <<
"enablelayer" << PP::space;
450 emitSymbol(cast<SymbolRefAttr>(layer));
455void Emitter::emitKnownLayers(ArrayRef<Attribute> layers) {
456 for (
auto layer : layers) {
458 ps.
cbox(2, IndentStyle::Block);
459 ps <<
"knownlayer" << PP::space;
460 emitSymbol(cast<SymbolRefAttr>(layer));
465void Emitter::emitRequirements(ArrayRef<Attribute> requirements) {
466 if (requirements.empty())
469 ps.
cbox(2, IndentStyle::Block);
470 ps <<
"requires" << PP::space;
471 llvm::interleaveComma(requirements, ps, [&](Attribute req) {
477void Emitter::emitParamAssign(ParamDeclAttr param, Operation *op,
478 std::optional<PPExtString> wordBeforeLHS) {
480 ps << *wordBeforeLHS << PP::nbsp;
482 ps <<
PPExtString(param.getName().strref()) << PP::nbsp <<
"=" << PP::nbsp;
483 emitParamValue(param.getValue(), op);
486void Emitter::emitParamValue(Attribute value, Operation *op) {
487 TypeSwitch<Attribute>(value)
488 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
489 .Case<FloatAttr>([&](
auto attr) {
491 attr.getValue().toString(str);
496 .Case<ArrayAttr>([&](
auto attr) {
499 interleaveComma(attr.getValue(),
500 [&](
auto element) { emitParamValue(element, op); });
504 .Case<DictionaryAttr>([&](
auto attr) {
507 interleaveComma(attr.getValue(), [&](
auto field) {
508 ps << PPExtString(field.getName()) << PP::nbsp <<
"=" << PP::nbsp;
509 emitParamValue(field.getValue(), op);
514 .Default([&](
auto attr) {
515 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
516 ps <<
"<unsupported-attr ";
522void Emitter::emitGenericIntrinsic(GenericIntrinsicOp op) {
526 ps << op.getIntrinsic();
528 auto params = op.getParameters();
529 if (!params.empty()) {
531 ps.scopedBox(PP::ibox0, [&]() {
533 params.getAsRange<ParamDeclAttr>(),
534 [&](ParamDeclAttr param) { emitParamAssign(param, op); });
539 if (op.getNumResults() != 0)
540 emitTypeWithColon(op.getResult().getType());
542 if (op.getNumOperands() != 0) {
543 ps <<
"," << PP::space;
544 ps.
scopedBox(PP::ibox0, [&]() { interleaveComma(op->getOperands()); });
551void Emitter::emitModule(FModuleOp op) {
553 ps.
cbox(4, IndentStyle::Block);
555 ps <<
"public" << PP::nbsp;
556 ps <<
"module " <<
PPExtString(legalize(op.getNameAttr()));
557 emitEnabledLayers(op.getLayers());
558 ps << PP::nbsp <<
":" << PP::end;
565 auto ports = op.getPorts();
566 emitModulePorts(ports, op.getArguments());
567 if (!ports.empty() && !op.getBodyBlock()->empty())
571 emitStatementsInBlock(*op.getBodyBlock());
574 valueNamesStorage.clear();
578void Emitter::emitModule(FExtModuleOp op) {
580 ps.
cbox(4, IndentStyle::Block);
581 ps <<
"extmodule " <<
PPExtString(legalize(op.getNameAttr()));
582 emitKnownLayers(op.getKnownLayers());
583 emitEnabledLayers(op.getLayers());
584 if (
auto reqs = op.getExternalRequirements())
585 emitRequirements(reqs.getValue());
586 ps << PP::nbsp <<
":" << PP::end;
593 auto ports = op.getPorts();
594 emitModulePorts(ports);
597 if (op.getDefname() && !op.getDefname()->empty()) {
599 ps <<
"defname = " <<
PPExtString(*op.getDefname());
604 emitModuleParameters(op, op.getParameters());
609void Emitter::emitModule(FIntModuleOp op) {
611 ps.
cbox(4, IndentStyle::Block);
612 ps <<
"intmodule " <<
PPExtString(legalize(op.getNameAttr()));
613 emitEnabledLayers(op.getLayers());
614 ps << PP::nbsp <<
":" << PP::end;
621 auto ports = op.getPorts();
622 emitModulePorts(ports);
625 ps <<
"intrinsic = " <<
PPExtString(op.getIntrinsic());
629 emitModuleParameters(op, op.getParameters());
636void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
637 Block::BlockArgListType arguments) {
639 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
641 const auto &port = ports[i];
642 ps << (port.direction == Direction::In ?
"input " :
"output ");
643 auto legalName = legalize(port.name);
644 if (!arguments.empty())
645 addValueName(arguments[i], legalName);
648 emitDomains(port.domains, ports);
649 emitLocation(ports[i].loc);
654void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
655 for (
auto param : parameters.getAsRange<ParamDeclAttr>()) {
657 emitParamAssign(param, op,
PPExtString(
"parameter"));
662void Emitter::emitDeclaration(DomainOp op) {
664 ps <<
"domain " <<
PPExtString(op.getSymName()) <<
" :";
665 emitLocationAndNewLine(op);
667 for (
auto attr : op.getFields()) {
668 auto fieldAttr = cast<DomainFieldAttr>(attr);
669 ps << PP::newline <<
PPExtString(fieldAttr.getName()) <<
" : ";
670 emitType(fieldAttr.getType());
676void Emitter::emitDeclaration(LayerOp op) {
678 ps <<
"layer " <<
PPExtString(op.getSymName()) <<
", "
679 <<
PPExtString(stringifyLayerConvention(op.getConvention()));
681 if (
auto outputFile = op->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
687 emitLocationAndNewLine(op);
689 for (
auto &bodyOp : op.getBody().getOps()) {
690 TypeSwitch<Operation *>(&bodyOp)
691 .Case<LayerOp>([&](
auto op) { emitDeclaration(op); })
692 .Default([&](
auto op) {
694 "not supported for emission inside layer definition");
701void Emitter::emitDeclaration(OptionOp op) {
703 ps <<
"option " <<
PPExtString(legalize(op.getSymNameAttr())) <<
" :";
706 for (
auto caseOp : op.getBody().getOps<OptionCaseOp>()) {
708 ps <<
PPExtString(legalize(caseOp.getSymNameAttr()));
709 emitLocation(caseOp);
712 ps << PP::newline << PP::newline;
716void Emitter::emitDeclaration(FormalOp op) {
717 emitFormalLike(op,
"formal", op.getSymNameAttr(),
718 op.getModuleNameAttr().getAttr(), op.getParameters());
722void Emitter::emitDeclaration(SimulationOp op) {
723 emitFormalLike(op,
"simulation", op.getSymNameAttr(),
724 op.getModuleNameAttr().getAttr(), op.getParameters());
728void Emitter::emitFormalLike(Operation *op, StringRef keyword,
729 StringAttr symName, StringAttr moduleName,
730 DictionaryAttr params) {
732 ps.
cbox(4, IndentStyle::Block);
733 ps << keyword <<
" " <<
PPExtString(legalize(symName));
735 ps << PP::nbsp <<
":" << PP::end;
740 for (
auto param : params) {
742 ps <<
PPExtString(param.getName()) << PP::nbsp <<
"=" << PP::nbsp;
743 emitParamValue(param.getValue(), op);
757 return (
isExpression(op) && !isa<InvalidValueOp>(op)) ||
758 (isa<GenericIntrinsicOp>(op) && op->hasOneUse() &&
762void Emitter::emitStatementsInBlock(Block &block) {
763 for (
auto &bodyOp : block) {
764 if (encounteredError)
768 TypeSwitch<Operation *>(&bodyOp)
769 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
770 PrintFOp, FPrintFOp, FFlushOp, AssertOp, AssumeOp, CoverOp,
771 ConnectOp, MatchingConnectOp, PropAssignOp, InstanceOp,
772 InstanceChoiceOp, AttachOp, MemOp, InvalidValueOp, SeqMemOp,
773 CombMemOp, MemoryPortOp, MemoryDebugPortOp, MemoryPortAccessOp,
774 DomainDefineOp, RefDefineOp, RefForceOp, RefForceInitialOp,
775 RefReleaseOp, RefReleaseInitialOp, LayerBlockOp,
776 GenericIntrinsicOp, DomainCreateAnonOp, DomainCreateOp>(
777 [&](
auto op) { emitStatement(op); })
778 .Default([&](
auto op) {
780 ps <<
"// operation " <<
PPExtString(op->getName().getStringRef());
782 emitOpError(op,
"not supported as statement");
787void Emitter::emitStatement(WhenOp op) {
790 emitExpression(op.getCondition());
792 emitLocationAndNewLine(op);
793 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
795 if (!op.hasElseRegion())
802 auto &elseBlock = op.getElseBlock();
803 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
804 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
805 emitStatement(whenOp);
812 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
815void Emitter::emitStatement(WireOp op) {
816 auto legalName = legalize(op.getNameAttr());
817 addForceable(op, legalName);
821 emitTypeWithColon(op.getResult().getType());
824 if (!op.getDomains().empty()) {
825 ps << PP::space <<
"domains" << PP::space <<
"[";
827 llvm::interleaveComma(op.getDomains(), ps, [&](Value domain) {
828 auto name = lookupEmittedName(domain);
829 assert(name &&
"domain value must have a name");
830 ps << PPExtString(*name);
836 emitLocationAndNewLine(op);
839void Emitter::emitStatement(RegOp op) {
840 auto legalName = legalize(op.getNameAttr());
841 addForceable(op, legalName);
845 emitTypeWithColon(op.getResult().getType());
846 ps <<
"," << PP::space;
847 emitExpression(op.getClockVal());
849 emitLocationAndNewLine(op);
852void Emitter::emitStatement(RegResetOp op) {
853 auto legalName = legalize(op.getNameAttr());
854 addForceable(op, legalName);
858 ps <<
"regreset " << legalName;
859 emitTypeWithColon(op.getResult().getType());
860 ps <<
"," << PP::space;
861 emitExpression(op.getClockVal());
862 ps <<
"," << PP::space;
863 emitExpression(op.getResetSignal());
864 ps <<
"," << PP::space;
865 emitExpression(op.getResetValue());
869 ps <<
"reg " << legalName;
870 emitTypeWithColon(op.getResult().getType());
871 ps <<
"," << PP::space;
872 emitExpression(op.getClockVal());
873 ps << PP::space <<
"with :";
875 ps << PP::neverbreak;
878 ps <<
"reset => (" << PP::ibox0;
879 emitExpression(op.getResetSignal());
880 ps <<
"," << PP::space;
881 emitExpression(op.getResetValue());
882 ps <<
")" << PP::end;
885 emitLocationAndNewLine(op);
888void Emitter::emitStatement(NodeOp op) {
889 auto legalName = legalize(op.getNameAttr());
890 addForceable(op, legalName);
892 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(legalName); },
893 [&]() { emitExpression(op.getInput()); });
894 emitLocationAndNewLine(op);
897void Emitter::emitStatement(StopOp op) {
900 ps <<
"stop(" << PP::ibox0;
901 emitExpression(op.getClock());
902 ps <<
"," << PP::space;
903 emitExpression(op.getCond());
904 ps <<
"," << PP::space;
906 ps <<
")" << PP::end;
907 if (!op.getName().empty()) {
908 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
911 emitLocationAndNewLine(op);
914void Emitter::emitStatement(SkipOp op) {
917 emitLocationAndNewLine(op);
920void Emitter::emitFormatString(Operation *op, StringRef origFormatString,
921 OperandRange substitutionOperands,
922 llvm::SmallVectorImpl<Value> &substitutions) {
931 SmallString<64> formatString;
932 for (
size_t i = 0, e = origFormatString.size(), opIdx = 0; i != e; ++i) {
933 auto c = origFormatString[i];
936 formatString.push_back(c);
939 SmallString<6> width;
940 c = origFormatString[++i];
943 c = origFormatString[++i];
952 formatString.append(width);
955 substitutions.push_back(substitutionOperands[opIdx++]);
958 formatString.push_back(c);
963 if (origFormatString.slice(i, i + 4) ==
"{{}}") {
964 formatString.append(
"{{");
965 TypeSwitch<Operation *>(substitutionOperands[opIdx++].getDefiningOp())
967 [&](
auto time) { formatString.append(
"SimulationTime"); })
968 .Case<HierarchicalModuleNameOp>([&](
auto time) {
969 formatString.append(
"HierarchicalModuleName");
972 emitError(op,
"unsupported fstring substitution type");
974 formatString.append(
"}}");
979 formatString.push_back(c);
985void Emitter::emitStatement(PrintFOp op) {
988 ps <<
"printf(" << PP::ibox0;
989 emitExpression(op.getClock());
990 ps <<
"," << PP::space;
991 emitExpression(op.getCond());
992 ps <<
"," << PP::space;
994 SmallVector<Value, 4> substitutions;
995 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
997 for (
auto operand : substitutions) {
998 ps <<
"," << PP::space;
999 emitExpression(operand);
1001 ps <<
")" << PP::end;
1002 if (!op.getName().empty()) {
1003 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1006 emitLocationAndNewLine(op);
1009void Emitter::emitStatement(FPrintFOp op) {
1012 ps <<
"fprintf(" << PP::ibox0;
1013 emitExpression(op.getClock());
1014 ps <<
"," << PP::space;
1015 emitExpression(op.getCond());
1016 ps <<
"," << PP::space;
1018 SmallVector<Value, 4> outputFileSubstitutions;
1019 emitFormatString(op, op.getOutputFile(), op.getOutputFileSubstitutions(),
1020 outputFileSubstitutions);
1021 if (!outputFileSubstitutions.empty()) {
1022 ps <<
"," << PP::space;
1023 interleaveComma(outputFileSubstitutions);
1026 ps <<
"," << PP::space;
1027 SmallVector<Value, 4> substitutions;
1028 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
1030 if (!substitutions.empty()) {
1031 ps <<
"," << PP::space;
1032 interleaveComma(substitutions);
1035 ps <<
")" << PP::end;
1036 if (!op.getName().empty()) {
1037 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1040 emitLocationAndNewLine(op);
1043void Emitter::emitStatement(FFlushOp op) {
1046 ps <<
"fflush(" << PP::ibox0;
1047 emitExpression(op.getClock());
1048 ps <<
"," << PP::space;
1049 emitExpression(op.getCond());
1050 if (op.getOutputFileAttr()) {
1051 ps <<
"," << PP::space;
1052 SmallVector<Value, 4> substitutions;
1053 emitFormatString(op, op.getOutputFileAttr(),
1054 op.getOutputFileSubstitutions(), substitutions);
1055 if (!substitutions.empty()) {
1056 ps <<
"," << PP::space;
1057 interleaveComma(substitutions);
1060 ps <<
")" << PP::end;
1062 emitLocationAndNewLine(op);
1066void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
1069 ps << mnemonic <<
"(" << PP::ibox0;
1070 emitExpression(op.getClock());
1071 ps <<
"," << PP::space;
1072 emitExpression(op.getPredicate());
1073 ps <<
"," << PP::space;
1074 emitExpression(op.getEnable());
1075 ps <<
"," << PP::space;
1077 ps <<
")" << PP::end;
1078 if (!op.getName().empty()) {
1079 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1082 emitLocationAndNewLine(op);
1085void Emitter::emitStatement(ConnectOp op) {
1089 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1090 ps <<
"invalidate" << PP::space;
1091 emitExpression(op.getDest());
1093 ps <<
"connect" << PP::space;
1094 emitExpression(op.getDest());
1095 ps <<
"," << PP::space;
1096 emitExpression(op.getSrc());
1100 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1101 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1103 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1106 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1109 emitLocationAndNewLine(op);
1112void Emitter::emitStatement(MatchingConnectOp op) {
1116 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1117 ps <<
"invalidate" << PP::space;
1118 emitExpression(op.getDest());
1120 ps <<
"connect" << PP::space;
1121 emitExpression(op.getDest());
1122 ps <<
"," << PP::space;
1123 emitExpression(op.getSrc());
1127 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1128 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1130 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1133 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1136 emitLocationAndNewLine(op);
1139void Emitter::emitStatement(PropAssignOp op) {
1142 ps <<
"propassign" << PP::space;
1143 interleaveComma(op.getOperands());
1145 emitLocationAndNewLine(op);
1148void Emitter::emitStatement(InstanceOp op) {
1150 auto legalName = legalize(op.getNameAttr());
1152 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
1153 emitLocationAndNewLine(op);
1157 SmallString<16> portName(legalName);
1158 portName.push_back(
'.');
1159 unsigned baseLen = portName.size();
1160 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1161 portName.append(legalize(op.getPortNameAttr(i)));
1162 addValueName(op.getResult(i), portName);
1163 portName.resize(baseLen);
1167void Emitter::emitStatement(InstanceChoiceOp op) {
1169 auto legalName = legalize(op.getNameAttr());
1170 ps <<
"instchoice " <<
PPExtString(legalName) <<
" of "
1171 <<
PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
1172 <<
PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
1175 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
1177 ps <<
PPExtString(legalize(optSym.getLeafReference()));
1182 setPendingNewline();
1184 SmallString<16> portName(legalName);
1185 portName.push_back(
'.');
1186 unsigned baseLen = portName.size();
1187 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1188 portName.append(legalize(op.getPortNameAttr(i)));
1189 addValueName(op.getResult(i), portName);
1190 portName.resize(baseLen);
1194void Emitter::emitStatement(AttachOp op) {
1195 emitStatementFunctionOp(
PPExtString(
"attach"), op);
1198void Emitter::emitStatement(MemOp op) {
1199 auto legalName = legalize(op.getNameAttr());
1200 SmallString<16> portName(legalName);
1201 portName.push_back(
'.');
1202 auto portNameBaseLen = portName.size();
1203 for (
auto result :
llvm::zip(op.getResults(), op.getPortNames())) {
1204 portName.resize(portNameBaseLen);
1205 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
1206 addValueName(std::get<0>(result), portName);
1211 emitLocationAndNewLine(op);
1214 ps <<
"data-type => ";
1215 emitType(op.getDataType());
1220 ps <<
"read-latency => ";
1223 ps <<
"write-latency => ";
1227 SmallString<16> reader, writer, readwriter;
1228 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
1229 auto add = [&](SmallString<16> &to, StringAttr name) {
1232 to.append(name.getValue());
1234 switch (port.second) {
1235 case MemOp::PortKind::Read:
1236 add(reader, legalize(port.first));
1238 case MemOp::PortKind::Write:
1239 add(writer, legalize(port.first));
1241 case MemOp::PortKind::ReadWrite:
1242 add(readwriter, legalize(port.first));
1244 case MemOp::PortKind::Debug:
1245 emitOpError(op,
"has unsupported 'debug' port");
1249 if (!reader.empty())
1250 ps <<
"reader => " << reader << PP::newline;
1251 if (!writer.empty())
1252 ps <<
"writer => " << writer << PP::newline;
1253 if (!readwriter.empty())
1254 ps <<
"readwriter => " << readwriter << PP::newline;
1256 ps <<
"read-under-write => ";
1257 emitAttribute(op.getRuwAttr());
1258 setPendingNewline();
1262void Emitter::emitStatement(SeqMemOp op) {
1265 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
1266 emitTypeWithColon(op.getType());
1267 ps <<
"," << PP::space;
1268 emitAttribute(op.getRuwAttr());
1270 emitLocationAndNewLine(op);
1273void Emitter::emitStatement(CombMemOp op) {
1276 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
1277 emitTypeWithColon(op.getType());
1279 emitLocationAndNewLine(op);
1282void Emitter::emitStatement(MemoryPortOp op) {
1284 addValueName(op.getData(), legalize(op.getNameAttr()));
1287void Emitter::emitStatement(MemoryDebugPortOp op) {
1289 addValueName(op.getData(), legalize(op.getNameAttr()));
1292void Emitter::emitStatement(MemoryPortAccessOp op) {
1296 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1297 emitAttribute(port.getDirection());
1299 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
1302 auto *mem = port.getMemory().getDefiningOp();
1303 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1304 ps << legalize(seqMem.getNameAttr());
1306 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1310 emitExpression(op.getIndex());
1314 emitExpression(op.getClock());
1316 emitLocationAndNewLine(op);
1319void Emitter::emitStatement(DomainDefineOp op) {
1321 if (isa_and_nonnull<DomainCreateAnonOp>(op.getSrc().getDefiningOp()))
1325 emitAssignLike([&]() { emitExpression(op.getDest()); },
1326 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1328 emitLocationAndNewLine(op);
1331void Emitter::emitStatement(RefDefineOp op) {
1333 emitAssignLike([&]() { emitExpression(op.getDest()); },
1334 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1336 emitLocationAndNewLine(op);
1339void Emitter::emitStatement(RefForceOp op) {
1340 emitStatementFunctionOp(
PPExtString(
"force"), op);
1343void Emitter::emitStatement(RefForceInitialOp op) {
1345 auto constantPredicate =
1346 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1347 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1350 emitExpression(op.getPredicate());
1351 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1353 ps <<
"force_initial(";
1355 interleaveComma({op.getDest(), op.getSrc()});
1360 emitLocationAndNewLine(op);
1363void Emitter::emitStatement(RefReleaseOp op) {
1364 emitStatementFunctionOp(
PPExtString(
"release"), op);
1367void Emitter::emitStatement(RefReleaseInitialOp op) {
1369 auto constantPredicate =
1370 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1371 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1374 emitExpression(op.getPredicate());
1375 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1377 ps <<
"release_initial(";
1378 emitExpression(op.getDest());
1382 emitLocationAndNewLine(op);
1385void Emitter::emitStatement(LayerBlockOp op) {
1387 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1388 emitLocationAndNewLine(op);
1389 auto *body = op.getBody();
1390 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1393void Emitter::emitStatement(InvalidValueOp op) {
1396 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1397 return use.getOperandNumber() == 1 &&
1398 isa<ConnectOp, MatchingConnectOp>(use.getOwner());
1404 auto name = circuitNamespace.newName(
"_invalid");
1405 addValueName(op, name);
1407 emitType(op.getType());
1408 emitLocationAndNewLine(op);
1414 emitLocationAndNewLine(op);
1417void Emitter::emitStatement(GenericIntrinsicOp op) {
1420 emitGenericIntrinsic(op);
1423 auto name = circuitNamespace.newName(
"_gen_int");
1424 addValueName(op.getResult(), name);
1425 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(name); },
1426 [&]() { emitGenericIntrinsic(op); });
1428 emitLocationAndNewLine(op);
1431void Emitter::emitStatement(DomainCreateAnonOp op) {
1435void Emitter::emitStatement(DomainCreateOp op) {
1437 auto name = legalize(op.getNameAttr());
1438 addValueName(op.getResult(), name);
1443 auto fieldValues = op.getFieldValues();
1444 if (fieldValues.empty())
1447 ps <<
"(" << PP::ibox0;
1448 interleaveComma(fieldValues, [&](
auto value) { emitExpression(value); });
1449 ps <<
")" << PP::end;
1452 emitLocationAndNewLine(op);
1455void Emitter::emitExpression(Value value) {
1458 if (
auto name = lookupEmittedName(value)) {
1464 auto op = value.getDefiningOp();
1465 assert(op &&
"value must either be a block arg or the result of an op");
1466 TypeSwitch<Operation *>(op)
1469 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1470 OpenSubfieldOp, OpenSubindexOp, DomainSubfieldOp,
1472 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1473 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1474 EQPrimOp, NEQPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1476 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsResetPrimOp,
1477 AsClockPrimOp, CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp,
1480 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1481 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1482 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1483 UnresolvedPathOp, GenericIntrinsicOp, CatPrimOp, UnsafeDomainCastOp,
1484 UnknownValueOp, StringConcatOp,
1486 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp,
1488 TimeOp>([&](
auto op) {
1489 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1491 .Default([&](
auto op) {
1492 emitOpError(op,
"not supported as expression");
1493 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1498void Emitter::emitExpression(ConstantOp op) {
1500 emitType(op.getType(),
false);
1507void Emitter::emitExpression(SpecialConstantOp op) {
1508 auto emitInner = [&]() {
1515 .
Case<ClockType>([&](
auto type) {
1520 .Case<ResetType>([&](
auto type) { emitInner(); })
1521 .Case<AsyncResetType>([&](
auto type) {
1522 ps <<
"asAsyncReset(";
1529void Emitter::emitExpression(SubfieldOp op) {
1530 BundleType type = op.getInput().getType();
1531 emitExpression(op.getInput());
1532 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1536void Emitter::emitExpression(SubindexOp op) {
1537 emitExpression(op.getInput());
1544void Emitter::emitExpression(SubaccessOp op) {
1545 emitExpression(op.getInput());
1547 emitExpression(op.getIndex());
1551void Emitter::emitExpression(OpenSubfieldOp op) {
1552 auto type = op.getInput().getType();
1553 emitExpression(op.getInput());
1554 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1558void Emitter::emitExpression(DomainSubfieldOp op) {
1559 emitExpression(op.getInput());
1560 ps <<
"." << legalize(op.getFieldName());
1563void Emitter::emitExpression(OpenSubindexOp op) {
1564 emitExpression(op.getInput());
1570void Emitter::emitExpression(RefSendOp op) {
1572 emitExpression(op.getBase());
1576void Emitter::emitExpression(RefResolveOp op) {
1578 emitExpression(op.getRef());
1582void Emitter::emitExpression(RefSubOp op) {
1583 emitExpression(op.getInput());
1585 .
Case<FVectorType>([&](
auto type) {
1591 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1594void Emitter::emitExpression(RWProbeOp op) {
1598 auto target = symInfos->get().irn.lookup(op.getTarget());
1600 if (target.isPort()) {
1601 auto mod = cast<FModuleOp>(target.getOp());
1602 auto port = target.getPort();
1603 base = mod.getArgument(port);
1605 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1608 emitExpression(base);
1611 auto fieldID = target.getField();
1612 auto type = base.getType();
1615 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1616 auto index = vecTy.getIndexForFieldID(fieldID);
1620 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1622 fieldID = subfieldID;
1624 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1625 auto index = bundleTy.getIndexForFieldID(fieldID);
1626 ps <<
"." << bundleTy.getElementName(index);
1627 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1629 fieldID = subfieldID;
1635void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1637void Emitter::emitExpression(UninferredResetCastOp op) {
1638 emitExpression(op.getInput());
1641void Emitter::emitExpression(FIntegerConstantOp op) {
1647void Emitter::emitExpression(BoolConstantOp op) {
1648 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1651void Emitter::emitExpression(DoubleConstantOp op) {
1657 SmallString<16> str;
1658 op.getValueAttr().getValue().toString(str);
1663void Emitter::emitExpression(StringConstantOp op) {
1669void Emitter::emitExpression(ListCreateOp op) {
1670 return emitLiteralExpression(op.getType(), op.getElements());
1673void Emitter::emitExpression(UnresolvedPathOp op) {
1679void Emitter::emitExpression(GenericIntrinsicOp op) {
1680 emitGenericIntrinsic(op);
1683void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1685void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1686 ArrayRef<uint32_t> attrs) {
1687 ps << mnemonic <<
"(" << PP::ibox0;
1688 interleaveComma(op->getOperands());
1689 if (!op->getOperands().empty() && !attrs.empty())
1690 ps <<
"," << PP::space;
1691 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1692 ps <<
")" << PP::end;
1695void Emitter::emitExpression(CatPrimOp op) {
1696 size_t numOperands = op.getNumOperands();
1697 switch (numOperands) {
1700 emitType(op.getType(),
false);
1704 auto operand = op->getOperand(0);
1706 if (isa<UIntType>(operand.getType()))
1707 return emitExpression(operand);
1710 ps <<
"cat(" << PP::ibox0;
1711 emitExpression(op->getOperand(0));
1712 ps <<
"," << PP::space <<
"SInt<0>(0))" << PP::end;
1718 for (
size_t i = 0; i < numOperands - 1; ++i) {
1719 ps <<
"cat(" << PP::ibox0;
1720 emitExpression(op->getOperand(i));
1721 ps <<
"," << PP::space;
1724 emitExpression(op->getOperand(numOperands - 1));
1725 for (
size_t i = 0; i < numOperands - 1; ++i)
1726 ps <<
")" << PP::end;
1731void Emitter::emitExpression(UnsafeDomainCastOp op) {
1732 ps <<
"unsafe_domain_cast(" << PP::ibox0;
1733 interleaveComma(op.getOperands(),
1734 [&](Value operand) { emitExpression(operand); });
1735 ps <<
")" << PP::end;
1738void Emitter::emitExpression(UnknownValueOp op) {
1740 emitType(op.getType());
1744void Emitter::emitAttribute(MemDirAttr attr) {
1746 case MemDirAttr::Infer:
1749 case MemDirAttr::Read:
1752 case MemDirAttr::Write:
1755 case MemDirAttr::ReadWrite:
1761void Emitter::emitAttribute(RUWBehaviorAttr attr) {
1762 switch (attr.getValue()) {
1763 case RUWBehavior::Undefined:
1766 case RUWBehavior::Old:
1769 case RUWBehavior::New:
1776void Emitter::emitType(Type type,
bool includeConst) {
1777 if (includeConst &&
isConst(type))
1779 auto emitWidth = [&](std::optional<int32_t> width) {
1788 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1789 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1790 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1791 .Case<UIntType>([&](
auto type) {
1793 emitWidth(type.getWidth());
1795 .Case<SIntType>([&](
auto type) {
1797 emitWidth(type.getWidth());
1799 .Case<AnalogType>([&](
auto type) {
1801 emitWidth(type.getWidth());
1803 .Case<OpenBundleType, BundleType>([&](
auto type) {
1805 if (!type.getElements().empty())
1807 bool anyEmitted =
false;
1809 for (
auto &element : type.getElements()) {
1811 ps <<
"," << PP::space;
1815 ps << legalize(element.name);
1816 emitTypeWithColon(element.type);
1825 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1826 emitType(type.getElementType());
1831 .Case<RefType>([&](RefType type) {
1832 if (type.getForceable())
1835 ps.
cbox(2, IndentStyle::Block);
1837 emitType(type.getType());
1838 if (
auto layer = type.getLayer()) {
1841 emitSymbol(type.getLayer());
1846 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1847 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1848 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1849 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1850 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1851 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1852 .Case<ListType>([&](ListType type) {
1854 emitType(type.getElementType());
1857 .Case<DomainType>([&](DomainType type) {
1858 ps <<
"Domain of " <<
PPExtString(type.getName().getValue());
1860 .Default([&](
auto type) {
1861 llvm_unreachable(
"all types should be implemented");
1865void Emitter::emitDomains(Attribute attr, ArrayRef<PortInfo> ports) {
1868 auto domains = cast<ArrayAttr>(attr);
1869 if (domains.empty())
1873 interleaveComma(domains, [&](Attribute attr) {
1874 ps.
addAsString(ports[cast<IntegerAttr>(attr).getUInt()].name.getValue());
1882void Emitter::emitLocation(Location loc) {
1884 ps << PP::neverbreak;
1886 dyn_cast_or_null<FileLineColLoc, LocationAttr>(LocationAttr(loc))) {
1887 ps <<
" @[" << fileLoc.getFilename().getValue();
1888 if (
auto line = fileLoc.getLine()) {
1891 if (
auto col = fileLoc.getColumn()) {
1908 std::optional<size_t> targetLineLength,
1910 Emitter emitter(os, version,
1911 targetLineLength.value_or(defaultTargetLineLength));
1912 for (
auto &op : *
module.getBody()) {
1913 if (auto circuitOp = dyn_cast<CircuitOp>(op))
1914 emitter.emitCircuit(circuitOp);
1916 return emitter.finalize();
1921 "target-line-length",
1922 llvm::cl::desc(
"Target line length for emitted .fir"),
1923 llvm::cl::value_desc(
"number of chars"),
1924 llvm::cl::init(defaultTargetLineLength));
1925 static mlir::TranslateFromMLIRRegistration toFIR(
1926 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
1927 [](ModuleOp module, llvm::raw_ostream &os) {
1930 [](mlir::DialectRegistry ®istry) {
1931 registry.insert<chirrtl::CHIRRTLDialect>();
1932 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.