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)
50 : pp(os, targetLineLength ? targetLineLength : defaultTargetLineLength, 0,
52 targetLineLength == 0),
53 ps(pp, saver), version(version) {
54 pp.setListener(&saver);
56 LogicalResult finalize();
59 void emitCircuit(CircuitOp op);
60 void emitModule(FModuleOp op);
61 void emitModule(FExtModuleOp op);
62 void emitModule(FIntModuleOp op);
63 void emitModulePorts(ArrayRef<PortInfo> ports,
64 Block::BlockArgListType arguments = {});
65 void emitModuleParameters(Operation *op, ArrayAttr parameters);
66 void emitDeclaration(DomainOp op);
67 void emitDeclaration(LayerOp op);
68 void emitDeclaration(OptionOp op);
69 void emitDeclaration(FormalOp op);
70 void emitDeclaration(SimulationOp op);
71 void emitFormalLike(Operation *op, StringRef keyword, StringAttr symName,
72 StringAttr moduleName, DictionaryAttr params);
73 void emitEnabledLayers(ArrayRef<Attribute> layers, Operation *op);
74 void emitKnownLayers(ArrayRef<Attribute> layers, Operation *op);
75 void emitRequirements(ArrayRef<Attribute> requirements);
76 void emitParamAssign(ParamDeclAttr param, Operation *op,
77 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
78 void emitParamValue(Attribute value, Operation *op);
80 void emitGenericIntrinsic(GenericIntrinsicOp op);
83 void emitStatementsInBlock(
Block &block);
84 void emitStatement(WhenOp op);
85 void emitStatement(WireOp op);
86 void emitStatement(RegOp op);
87 void emitStatement(RegResetOp op);
88 void emitStatement(NodeOp op);
89 void emitStatement(StopOp op);
90 void emitStatement(SkipOp op);
91 void emitFormatString(Operation *op, StringRef formatString, OperandRange ops,
92 llvm::SmallVectorImpl<Value> &substitutions);
94 void emitPrintfLike(T op, StringAttr fileName);
95 void emitStatement(PrintFOp op);
96 void emitStatement(FPrintFOp op);
97 void emitStatement(FFlushOp op);
98 void emitStatement(ConnectOp op);
99 void emitStatement(MatchingConnectOp op);
100 void emitStatement(PropertyAssertOp op);
101 void emitStatement(PropAssignOp op);
102 void emitStatement(InstanceOp op);
103 void emitStatement(InstanceChoiceOp op);
104 void emitStatement(AttachOp op);
105 void emitStatement(MemOp op);
106 void emitStatement(InvalidValueOp op);
107 void emitStatement(CombMemOp op);
108 void emitStatement(SeqMemOp op);
109 void emitStatement(MemoryPortOp op);
110 void emitStatement(MemoryDebugPortOp op);
111 void emitStatement(MemoryPortAccessOp op);
112 void emitStatement(DomainDefineOp op);
113 void emitStatement(RefDefineOp op);
114 void emitStatement(RefForceOp op);
115 void emitStatement(RefForceInitialOp op);
116 void emitStatement(RefReleaseOp op);
117 void emitStatement(RefReleaseInitialOp op);
118 void emitStatement(LayerBlockOp op);
119 void emitStatement(GenericIntrinsicOp op);
120 void emitStatement(DomainCreateAnonOp op);
121 void emitStatement(DomainCreateOp op);
124 void emitVerifStatement(T op, StringRef mnemonic);
125 void emitStatement(AssertOp op) { emitVerifStatement(op,
"assert"); }
126 void emitStatement(AssumeOp op) { emitVerifStatement(op,
"assume"); }
127 void emitStatement(CoverOp op) { emitVerifStatement(op,
"cover"); }
130 void emitExpression(Value value);
131 void emitExpression(ConstantOp op);
132 void emitExpression(SpecialConstantOp op);
133 void emitExpression(SubfieldOp op);
134 void emitExpression(SubindexOp op);
135 void emitExpression(SubaccessOp op);
136 void emitExpression(OpenSubfieldOp op);
137 void emitExpression(DomainSubfieldOp op);
138 void emitExpression(OpenSubindexOp op);
139 void emitExpression(RefResolveOp op);
140 void emitExpression(RefSendOp op);
141 void emitExpression(RefSubOp op);
142 void emitExpression(RWProbeOp op);
143 void emitExpression(RefCastOp op);
144 void emitExpression(UninferredResetCastOp op);
145 void emitExpression(ConstCastOp op);
146 void emitExpression(StringConstantOp op);
147 void emitExpression(FIntegerConstantOp op);
148 void emitExpression(BoolConstantOp op);
149 void emitExpression(DoubleConstantOp op);
150 void emitExpression(ListCreateOp op);
151 void emitExpression(UnresolvedPathOp op);
152 void emitExpression(GenericIntrinsicOp op);
153 void emitExpression(CatPrimOp op);
154 void emitExpression(UnsafeDomainCastOp op);
155 void emitExpression(UnknownValueOp op);
157 void emitPrimExpr(StringRef mnemonic, Operation *op,
158 ArrayRef<uint32_t> attrs = {});
160 void emitExpression(BitsPrimOp op) {
161 emitPrimExpr(
"bits", op, {op.getHi(), op.getLo()});
163 void emitExpression(HeadPrimOp op) {
164 emitPrimExpr(
"head", op, op.getAmount());
166 void emitExpression(TailPrimOp op) {
167 emitPrimExpr(
"tail", op, op.getAmount());
169 void emitExpression(PadPrimOp op) { emitPrimExpr(
"pad", op, op.getAmount()); }
170 void emitExpression(ShlPrimOp op) { emitPrimExpr(
"shl", op, op.getAmount()); }
171 void emitExpression(ShrPrimOp op) { emitPrimExpr(
"shr", op, op.getAmount()); }
173 void emitExpression(TimeOp op) {}
176#define HANDLE(OPTYPE, MNEMONIC) \
177 void emitExpression(OPTYPE op) { emitPrimExpr(MNEMONIC, op); }
192 HANDLE(DShlPrimOp,
"dshl");
193 HANDLE(DShlwPrimOp,
"dshlw");
194 HANDLE(DShrPrimOp,
"dshr");
196 HANDLE(AsSIntPrimOp,
"asSInt");
197 HANDLE(AsUIntPrimOp,
"asUInt");
198 HANDLE(AsAsyncResetPrimOp,
"asAsyncReset");
199 HANDLE(AsResetPrimOp,
"asReset");
200 HANDLE(AsClockPrimOp,
"asClock");
204 HANDLE(AndRPrimOp,
"andr");
206 HANDLE(XorRPrimOp,
"xorr");
207 HANDLE(StringConcatOp,
"string_concat");
210 void emitExpression(PropEqOp op) {
211 if (failed(requireVersion({6, 0, 0}, op,
"property equality")))
213 emitPrimExpr(
"prop_eq", op);
216 void emitExpression(BoolAndOp op) {
217 if (failed(requireVersion({6, 0, 0}, op,
"boolean and")))
219 emitPrimExpr(
"bool_and", op);
222 void emitExpression(BoolOrOp op) {
223 if (failed(requireVersion({6, 0, 0}, op,
"boolean or")))
225 emitPrimExpr(
"bool_or", op);
228 void emitExpression(BoolXorOp op) {
229 if (failed(requireVersion({6, 0, 0}, op,
"boolean xor")))
231 emitPrimExpr(
"bool_xor", op);
235 void emitAttribute(MemDirAttr attr);
236 void emitAttribute(RUWBehaviorAttr attr);
239 void emitType(Type type,
bool includeConst =
true);
240 void emitTypeWithColon(Type type) {
241 ps << PP::space <<
":" << PP::nbsp;
246 void emitDomains(Attribute attr, ArrayRef<PortInfo> ports);
249 void emitLocation(Location loc);
250 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
251 template <
typename... Args>
252 void emitLocationAndNewLine(Args... args) {
255 ps << PP::neverbreak;
256 emitLocation(args...);
260 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
261 llvm::function_ref<
void()> emitRHS,
263 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
265 ps.scopedBox(PP::ibox2, [&]() {
267 ps << *wordBeforeLHS << PP::space;
271 ps << PP::space << syntax << PP::nbsp;
273 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
278 void emitSubExprIBox2(Value v) {
279 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
284 template <
typename Container,
typename EachFn>
285 void interleaveComma(
const Container &c, EachFn eachFn) {
286 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
291 void interleaveComma(ValueRange ops) {
292 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
295 void emitStatementFunctionOp(
PPExtString name, Operation *op) {
298 ps.scopedBox(PP::ibox0, [&]() {
299 interleaveComma(op->getOperands());
302 emitLocationAndNewLine(op);
305 template <
typename EachFn,
typename Range>
306 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
309 ps.scopedBox(PP::ibox0, [&]() {
310 interleaveComma(r, eachFn);
315 void emitLiteralExpression(Type type, ValueRange values) {
316 return emitLiteralExpression(type, values,
317 [&](Value v) { emitSubExprIBox2(v); });
321 void emitSymbol(SymbolRefAttr symbol) {
322 ps.ibox(2, IndentStyle::Block);
323 ps << symbol.getRootReference();
324 for (
auto nested : symbol.getNestedReferences()) {
327 ps << nested.getAttr();
334 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
335 encounteredError =
true;
336 return op->emitError(message);
340 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
341 encounteredError =
true;
342 return op->emitOpError(message);
346 LogicalResult requireVersion(
FIRVersion minVersion, Operation *op,
348 if (version >= minVersion)
351 return emitOpError(op, feature +
" requires FIRRTL ") << minVersion;
356 std::optional<StringRef> lookupEmittedName(Value value) {
357 auto it = valueNames.find(value);
358 if (it != valueNames.end())
365 void emitPendingNewlineIfNeeded() {
366 if (pendingNewline) {
367 pendingNewline =
false;
371 void setPendingNewline() {
373 pendingNewline =
true;
376 void startStatement() { emitPendingNewlineIfNeeded(); }
394 bool pendingNewline =
false;
397 bool encounteredError =
false;
402 DenseMap<Value, StringRef> valueNames;
403 StringSet<> valueNamesStorage;
407 StringAttr legalize(StringAttr attr) {
408 StringRef str = attr.getValue();
409 if (str.empty() || !
isdigit(str.front()))
411 return StringAttr::get(attr.getContext(),
"`" + Twine(attr) +
"`");
414 void addValueName(Value value, StringAttr attr) {
415 valueNames.insert({value, attr.getValue()});
417 void addValueName(Value value, StringRef str) {
418 auto it = valueNamesStorage.insert(str);
419 valueNames.insert({value, it.first->getKey()});
421 void addForceable(Forceable op, StringAttr attr) {
422 addValueName(op.getData(), attr);
423 if (op.isForceable()) {
424 SmallString<32> rwName;
425 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
426 addValueName(op.getDataRef(), rwName);
435 SymbolTable symbolTable;
438 SymInfos(Operation *op) : symbolTable(op), istc(op) {}
440 std::optional<std::reference_wrapper<SymInfos>> symInfos;
447LogicalResult Emitter::finalize() {
return failure(encounteredError); }
450void Emitter::emitCircuit(CircuitOp op) {
451 circuitNamespace.add(op);
452 SymInfos circuitSymInfos(op);
453 symInfos = circuitSymInfos;
455 ps <<
"FIRRTL version ";
462 ps <<
"circuit " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
466 if (encounteredError)
468 TypeSwitch<Operation *>(&bodyOp)
469 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](
auto op) {
473 .Case<DomainOp, LayerOp, OptionOp, FormalOp, SimulationOp>(
474 [&](
auto op) { emitDeclaration(op); })
475 .Default([&](
auto op) {
476 emitOpError(op,
"not supported for emission inside circuit");
480 circuitNamespace.clear();
481 symInfos = std::nullopt;
484void Emitter::emitEnabledLayers(ArrayRef<Attribute> layers, Operation *op) {
487 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"enabled layers")))
489 for (
auto layer : layers) {
491 ps.
cbox(2, IndentStyle::Block);
492 ps <<
"enablelayer" << PP::space;
493 emitSymbol(cast<SymbolRefAttr>(layer));
498void Emitter::emitKnownLayers(ArrayRef<Attribute> layers, Operation *op) {
501 if (failed(requireVersion({6, 0, 0}, op,
"known layers")))
503 for (
auto layer : layers) {
505 ps.
cbox(2, IndentStyle::Block);
506 ps <<
"knownlayer" << PP::space;
507 emitSymbol(cast<SymbolRefAttr>(layer));
512void Emitter::emitRequirements(ArrayRef<Attribute> requirements) {
513 if (requirements.empty())
516 ps.
cbox(2, IndentStyle::Block);
517 ps <<
"requires" << PP::space;
518 llvm::interleaveComma(requirements, ps, [&](Attribute req) {
524void Emitter::emitParamAssign(ParamDeclAttr param, Operation *op,
525 std::optional<PPExtString> wordBeforeLHS) {
527 ps << *wordBeforeLHS << PP::nbsp;
529 ps <<
PPExtString(param.getName().strref()) << PP::nbsp <<
"=" << PP::nbsp;
530 emitParamValue(param.getValue(), op);
533void Emitter::emitParamValue(Attribute value, Operation *op) {
534 TypeSwitch<Attribute>(value)
535 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
536 .Case<FloatAttr>([&](
auto attr) {
538 attr.getValue().toString(str);
543 .Case<ArrayAttr>([&](
auto attr) {
546 interleaveComma(attr.getValue(),
547 [&](
auto element) { emitParamValue(element, op); });
551 .Case<DictionaryAttr>([&](
auto attr) {
554 interleaveComma(attr.getValue(), [&](
auto field) {
555 ps << PPExtString(field.getName()) << PP::nbsp <<
"=" << PP::nbsp;
556 emitParamValue(field.getValue(), op);
561 .Default([&](
auto attr) {
562 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
563 ps <<
"<unsupported-attr ";
569void Emitter::emitGenericIntrinsic(GenericIntrinsicOp op) {
573 ps << op.getIntrinsic();
575 auto params = op.getParameters();
576 if (!params.empty()) {
578 ps.scopedBox(PP::ibox0, [&]() {
580 params.getAsRange<ParamDeclAttr>(),
581 [&](ParamDeclAttr param) { emitParamAssign(param, op); });
586 if (op.getNumResults() != 0)
587 emitTypeWithColon(op.getResult().getType());
589 if (op.getNumOperands() != 0) {
590 ps <<
"," << PP::space;
591 ps.
scopedBox(PP::ibox0, [&]() { interleaveComma(op->getOperands()); });
598void Emitter::emitModule(FModuleOp op) {
600 ps.
cbox(4, IndentStyle::Block);
601 if (op.isPublic() &&
FIRVersion(3, 3, 0) <= version)
602 ps <<
"public" << PP::nbsp;
603 ps <<
"module " <<
PPExtString(legalize(op.getNameAttr()));
604 emitEnabledLayers(op.getLayers(), op);
605 ps << PP::nbsp <<
":" << PP::end;
612 auto ports = op.getPorts();
613 emitModulePorts(ports, op.getArguments());
614 if (!ports.empty() && !op.getBodyBlock()->empty())
618 emitStatementsInBlock(*op.getBodyBlock());
621 valueNamesStorage.clear();
625void Emitter::emitModule(FExtModuleOp op) {
627 ps.
cbox(4, IndentStyle::Block);
628 ps <<
"extmodule " <<
PPExtString(legalize(op.getNameAttr()));
629 emitKnownLayers(op.getKnownLayers(), op);
630 emitEnabledLayers(op.getLayers(), op);
631 if (
auto reqs = op.getExternalRequirements())
632 emitRequirements(reqs.getValue());
633 ps << PP::nbsp <<
":" << PP::end;
640 auto ports = op.getPorts();
641 emitModulePorts(ports);
644 if (op.getDefname() && !op.getDefname()->empty()) {
646 ps <<
"defname = " <<
PPExtString(*op.getDefname());
651 emitModuleParameters(op, op.getParameters());
656void Emitter::emitModule(FIntModuleOp op) {
658 emitOpError(op,
"intrinsic modules were removed in FIRRTL 4.0.0");
662 ps.
cbox(4, IndentStyle::Block);
663 ps <<
"intmodule " <<
PPExtString(legalize(op.getNameAttr()));
664 emitEnabledLayers(op.getLayers(), op);
665 ps << PP::nbsp <<
":" << PP::end;
672 auto ports = op.getPorts();
673 emitModulePorts(ports);
676 ps <<
"intrinsic = " <<
PPExtString(op.getIntrinsic());
680 emitModuleParameters(op, op.getParameters());
687void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
688 Block::BlockArgListType arguments) {
690 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
692 const auto &port = ports[i];
693 ps << (port.direction == Direction::In ?
"input " :
"output ");
694 auto legalName = legalize(port.name);
695 if (!arguments.empty())
696 addValueName(arguments[i], legalName);
699 emitDomains(port.domains, ports);
700 emitLocation(ports[i].loc);
705void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
706 for (
auto param : parameters.getAsRange<ParamDeclAttr>()) {
708 emitParamAssign(param, op,
PPExtString(
"parameter"));
713void Emitter::emitDeclaration(DomainOp op) {
717 ps <<
"domain " <<
PPExtString(op.getSymName()) <<
" :";
718 emitLocationAndNewLine(op);
720 for (
auto attr : op.getFields()) {
721 auto fieldAttr = cast<DomainFieldAttr>(attr);
722 ps << PP::newline <<
PPExtString(fieldAttr.getName()) <<
" : ";
723 emitType(fieldAttr.getType());
729void Emitter::emitDeclaration(LayerOp op) {
730 if (failed(requireVersion(
FIRVersion(3, 3, 0), op,
"layers")))
732 if (op.getConvention() == LayerConvention::Inline &&
733 failed(requireVersion(
FIRVersion(4, 1, 0), op,
"inline layers")))
736 ps <<
"layer " <<
PPExtString(op.getSymName()) <<
", "
737 <<
PPExtString(stringifyLayerConvention(op.getConvention()));
739 if (
auto outputFile = op->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
745 emitLocationAndNewLine(op);
747 for (
auto &bodyOp : op.getBody().getOps()) {
748 TypeSwitch<Operation *>(&bodyOp)
749 .Case<LayerOp>([&](
auto op) { emitDeclaration(op); })
750 .Default([&](
auto op) {
752 "not supported for emission inside layer definition");
759void Emitter::emitDeclaration(OptionOp op) {
763 ps <<
"option " <<
PPExtString(legalize(op.getSymNameAttr())) <<
" :";
766 for (
auto caseOp : op.getBody().getOps<OptionCaseOp>()) {
768 ps <<
PPExtString(legalize(caseOp.getSymNameAttr()));
769 emitLocation(caseOp);
772 ps << PP::newline << PP::newline;
776void Emitter::emitDeclaration(FormalOp op) {
777 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"formal tests")))
779 emitFormalLike(op,
"formal", op.getSymNameAttr(),
780 op.getModuleNameAttr().getAttr(), op.getParameters());
784void Emitter::emitDeclaration(SimulationOp op) {
785 if (failed(requireVersion(
nextFIRVersion, op,
"simulation tests")))
787 emitFormalLike(op,
"simulation", op.getSymNameAttr(),
788 op.getModuleNameAttr().getAttr(), op.getParameters());
792void Emitter::emitFormalLike(Operation *op, StringRef keyword,
793 StringAttr symName, StringAttr moduleName,
794 DictionaryAttr params) {
796 ps.
cbox(4, IndentStyle::Block);
797 ps << keyword <<
" " <<
PPExtString(legalize(symName));
799 ps << PP::nbsp <<
":" << PP::end;
804 for (
auto param : params) {
806 ps <<
PPExtString(param.getName()) << PP::nbsp <<
"=" << PP::nbsp;
807 emitParamValue(param.getValue(), op);
821 return (
isExpression(op) && !isa<InvalidValueOp>(op)) ||
822 (isa<GenericIntrinsicOp>(op) && op->hasOneUse() &&
826void Emitter::emitStatementsInBlock(Block &block) {
827 for (
auto &bodyOp : block) {
828 if (encounteredError)
832 TypeSwitch<Operation *>(&bodyOp)
833 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
834 PrintFOp, FPrintFOp, FFlushOp, AssertOp, AssumeOp, CoverOp,
835 ConnectOp, MatchingConnectOp, PropertyAssertOp, PropAssignOp,
836 InstanceOp, InstanceChoiceOp, AttachOp, MemOp, InvalidValueOp,
837 SeqMemOp, CombMemOp, MemoryPortOp, MemoryDebugPortOp,
838 MemoryPortAccessOp, DomainDefineOp, RefDefineOp, RefForceOp,
839 RefForceInitialOp, RefReleaseOp, RefReleaseInitialOp,
840 LayerBlockOp, GenericIntrinsicOp, DomainCreateAnonOp,
841 DomainCreateOp>([&](
auto op) { emitStatement(op); })
842 .Default([&](
auto op) {
844 ps <<
"// operation " <<
PPExtString(op->getName().getStringRef());
846 emitOpError(op,
"not supported as statement");
851void Emitter::emitStatement(WhenOp op) {
854 emitExpression(op.getCondition());
856 emitLocationAndNewLine(op);
857 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
859 if (!op.hasElseRegion())
866 auto &elseBlock = op.getElseBlock();
867 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
868 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
869 emitStatement(whenOp);
876 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
879void Emitter::emitStatement(WireOp op) {
880 auto legalName = legalize(op.getNameAttr());
881 addForceable(op, legalName);
885 emitTypeWithColon(op.getResult().getType());
888 if (!op.getDomains().empty()) {
889 ps << PP::space <<
"domains" << PP::space <<
"[";
891 llvm::interleaveComma(op.getDomains(), ps, [&](Value domain) {
892 auto name = lookupEmittedName(domain);
893 assert(name &&
"domain value must have a name");
894 ps << PPExtString(*name);
900 emitLocationAndNewLine(op);
903void Emitter::emitStatement(RegOp op) {
904 auto legalName = legalize(op.getNameAttr());
905 addForceable(op, legalName);
909 emitTypeWithColon(op.getResult().getType());
910 ps <<
"," << PP::space;
911 emitExpression(op.getClockVal());
913 emitLocationAndNewLine(op);
916void Emitter::emitStatement(RegResetOp op) {
917 auto legalName = legalize(op.getNameAttr());
918 addForceable(op, legalName);
922 ps <<
"regreset " << legalName;
923 emitTypeWithColon(op.getResult().getType());
924 ps <<
"," << PP::space;
925 emitExpression(op.getClockVal());
926 ps <<
"," << PP::space;
927 emitExpression(op.getResetSignal());
928 ps <<
"," << PP::space;
929 emitExpression(op.getResetValue());
933 ps <<
"reg " << legalName;
934 emitTypeWithColon(op.getResult().getType());
935 ps <<
"," << PP::space;
936 emitExpression(op.getClockVal());
937 ps << PP::space <<
"with :";
939 ps << PP::neverbreak;
942 ps <<
"reset => (" << PP::ibox0;
943 emitExpression(op.getResetSignal());
944 ps <<
"," << PP::space;
945 emitExpression(op.getResetValue());
946 ps <<
")" << PP::end;
949 emitLocationAndNewLine(op);
952void Emitter::emitStatement(NodeOp op) {
953 auto legalName = legalize(op.getNameAttr());
954 addForceable(op, legalName);
956 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(legalName); },
957 [&]() { emitExpression(op.getInput()); });
958 emitLocationAndNewLine(op);
961void Emitter::emitStatement(StopOp op) {
964 ps <<
"stop(" << PP::ibox0;
965 emitExpression(op.getClock());
966 ps <<
"," << PP::space;
967 emitExpression(op.getCond());
968 ps <<
"," << PP::space;
970 ps <<
")" << PP::end;
971 if (!op.getName().empty()) {
972 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
975 emitLocationAndNewLine(op);
978void Emitter::emitStatement(SkipOp op) {
981 emitLocationAndNewLine(op);
984void Emitter::emitFormatString(Operation *op, StringRef origFormatString,
985 OperandRange substitutionOperands,
986 llvm::SmallVectorImpl<Value> &substitutions) {
995 SmallString<64> formatString;
996 for (
size_t i = 0, e = origFormatString.size(), opIdx = 0; i != e; ++i) {
997 auto c = origFormatString[i];
1000 formatString.push_back(c);
1003 SmallString<6> width;
1004 c = origFormatString[++i];
1007 c = origFormatString[++i];
1016 formatString.append(width);
1019 substitutions.push_back(substitutionOperands[opIdx++]);
1022 formatString.push_back(c);
1027 if (origFormatString.slice(i, i + 4) ==
"{{}}") {
1028 formatString.append(
"{{");
1029 TypeSwitch<Operation *>(substitutionOperands[opIdx++].getDefiningOp())
1031 [&](
auto time) { formatString.append(
"SimulationTime"); })
1032 .Case<HierarchicalModuleNameOp>([&](
auto time) {
1033 formatString.append(
"HierarchicalModuleName");
1035 .Default([&](
auto) {
1036 emitError(op,
"unsupported fstring substitution type");
1038 formatString.append(
"}}");
1043 formatString.push_back(c);
1049void Emitter::emitStatement(PrintFOp op) {
1052 ps <<
"printf(" << PP::ibox0;
1053 emitExpression(op.getClock());
1054 ps <<
"," << PP::space;
1055 emitExpression(op.getCond());
1056 ps <<
"," << PP::space;
1058 SmallVector<Value, 4> substitutions;
1059 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
1061 for (
auto operand : substitutions) {
1062 ps <<
"," << PP::space;
1063 emitExpression(operand);
1065 ps <<
")" << PP::end;
1066 if (!op.getName().empty()) {
1067 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1070 emitLocationAndNewLine(op);
1073void Emitter::emitStatement(FPrintFOp op) {
1074 if (failed(requireVersion({6, 0, 0}, op,
"fprintf")))
1078 ps <<
"fprintf(" << PP::ibox0;
1079 emitExpression(op.getClock());
1080 ps <<
"," << PP::space;
1081 emitExpression(op.getCond());
1082 ps <<
"," << PP::space;
1084 SmallVector<Value, 4> outputFileSubstitutions;
1085 emitFormatString(op, op.getOutputFile(), op.getOutputFileSubstitutions(),
1086 outputFileSubstitutions);
1087 if (!outputFileSubstitutions.empty()) {
1088 ps <<
"," << PP::space;
1089 interleaveComma(outputFileSubstitutions);
1092 ps <<
"," << PP::space;
1093 SmallVector<Value, 4> substitutions;
1094 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
1096 if (!substitutions.empty()) {
1097 ps <<
"," << PP::space;
1098 interleaveComma(substitutions);
1101 ps <<
")" << PP::end;
1102 if (!op.getName().empty()) {
1103 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1106 emitLocationAndNewLine(op);
1109void Emitter::emitStatement(FFlushOp op) {
1110 if (failed(requireVersion({6, 0, 0}, op,
"fflush")))
1114 ps <<
"fflush(" << PP::ibox0;
1115 emitExpression(op.getClock());
1116 ps <<
"," << PP::space;
1117 emitExpression(op.getCond());
1118 if (op.getOutputFileAttr()) {
1119 ps <<
"," << PP::space;
1120 SmallVector<Value, 4> substitutions;
1121 emitFormatString(op, op.getOutputFileAttr(),
1122 op.getOutputFileSubstitutions(), substitutions);
1123 if (!substitutions.empty()) {
1124 ps <<
"," << PP::space;
1125 interleaveComma(substitutions);
1128 ps <<
")" << PP::end;
1130 emitLocationAndNewLine(op);
1134void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
1137 ps << mnemonic <<
"(" << PP::ibox0;
1138 emitExpression(op.getClock());
1139 ps <<
"," << PP::space;
1140 emitExpression(op.getPredicate());
1141 ps <<
"," << PP::space;
1142 emitExpression(op.getEnable());
1143 ps <<
"," << PP::space;
1145 ps <<
")" << PP::end;
1146 if (!op.getName().empty()) {
1147 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1150 emitLocationAndNewLine(op);
1153void Emitter::emitStatement(ConnectOp op) {
1157 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1158 ps <<
"invalidate" << PP::space;
1159 emitExpression(op.getDest());
1161 ps <<
"connect" << PP::space;
1162 emitExpression(op.getDest());
1163 ps <<
"," << PP::space;
1164 emitExpression(op.getSrc());
1168 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1169 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1171 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1174 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1177 emitLocationAndNewLine(op);
1180void Emitter::emitStatement(MatchingConnectOp op) {
1184 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1185 ps <<
"invalidate" << PP::space;
1186 emitExpression(op.getDest());
1188 ps <<
"connect" << PP::space;
1189 emitExpression(op.getDest());
1190 ps <<
"," << PP::space;
1191 emitExpression(op.getSrc());
1195 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1196 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1198 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1201 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1204 emitLocationAndNewLine(op);
1207void Emitter::emitStatement(PropertyAssertOp op) {
1210 ps <<
"propassert" << PP::space;
1211 emitExpression(op.getCondition());
1212 ps <<
"," << PP::space;
1215 emitLocationAndNewLine(op);
1218void Emitter::emitStatement(PropAssignOp op) {
1219 if (failed(requireVersion(
FIRVersion(3, 1, 0), op,
"properties")))
1223 ps <<
"propassign" << PP::space;
1224 interleaveComma(op.getOperands());
1226 emitLocationAndNewLine(op);
1229void Emitter::emitStatement(InstanceOp op) {
1231 auto legalName = legalize(op.getNameAttr());
1233 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
1234 emitLocationAndNewLine(op);
1238 SmallString<16> portName(legalName);
1239 portName.push_back(
'.');
1240 unsigned baseLen = portName.size();
1241 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1242 portName.append(legalize(op.getPortNameAttr(i)));
1243 addValueName(op.getResult(i), portName);
1244 portName.resize(baseLen);
1248void Emitter::emitStatement(InstanceChoiceOp op) {
1250 "option groups/instance choices")))
1253 auto legalName = legalize(op.getNameAttr());
1254 ps <<
"instchoice " <<
PPExtString(legalName) <<
" of "
1255 <<
PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
1256 <<
PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
1259 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
1261 ps <<
PPExtString(legalize(optSym.getLeafReference()));
1266 setPendingNewline();
1268 SmallString<16> portName(legalName);
1269 portName.push_back(
'.');
1270 unsigned baseLen = portName.size();
1271 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1272 portName.append(legalize(op.getPortNameAttr(i)));
1273 addValueName(op.getResult(i), portName);
1274 portName.resize(baseLen);
1278void Emitter::emitStatement(AttachOp op) {
1279 emitStatementFunctionOp(
PPExtString(
"attach"), op);
1282void Emitter::emitStatement(MemOp op) {
1283 auto legalName = legalize(op.getNameAttr());
1284 SmallString<16> portName(legalName);
1285 portName.push_back(
'.');
1286 auto portNameBaseLen = portName.size();
1287 for (
auto result :
llvm::zip(op.getResults(), op.getPortNames())) {
1288 portName.resize(portNameBaseLen);
1289 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
1290 addValueName(std::get<0>(result), portName);
1295 emitLocationAndNewLine(op);
1298 ps <<
"data-type => ";
1299 emitType(op.getDataType());
1304 ps <<
"read-latency => ";
1307 ps <<
"write-latency => ";
1311 SmallString<16> reader, writer, readwriter;
1312 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
1313 auto add = [&](SmallString<16> &to, StringAttr name) {
1316 to.append(name.getValue());
1318 switch (port.second) {
1319 case MemOp::PortKind::Read:
1320 add(reader, legalize(port.first));
1322 case MemOp::PortKind::Write:
1323 add(writer, legalize(port.first));
1325 case MemOp::PortKind::ReadWrite:
1326 add(readwriter, legalize(port.first));
1328 case MemOp::PortKind::Debug:
1329 emitOpError(op,
"has unsupported 'debug' port");
1333 if (!reader.empty())
1334 ps <<
"reader => " << reader << PP::newline;
1335 if (!writer.empty())
1336 ps <<
"writer => " << writer << PP::newline;
1337 if (!readwriter.empty())
1338 ps <<
"readwriter => " << readwriter << PP::newline;
1340 ps <<
"read-under-write => ";
1341 emitAttribute(op.getRuwAttr());
1342 setPendingNewline();
1346void Emitter::emitStatement(SeqMemOp op) {
1349 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
1350 emitTypeWithColon(op.getType());
1351 ps <<
"," << PP::space;
1352 emitAttribute(op.getRuwAttr());
1354 emitLocationAndNewLine(op);
1357void Emitter::emitStatement(CombMemOp op) {
1360 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
1361 emitTypeWithColon(op.getType());
1363 emitLocationAndNewLine(op);
1366void Emitter::emitStatement(MemoryPortOp op) {
1368 addValueName(op.getData(), legalize(op.getNameAttr()));
1371void Emitter::emitStatement(MemoryDebugPortOp op) {
1373 addValueName(op.getData(), legalize(op.getNameAttr()));
1376void Emitter::emitStatement(MemoryPortAccessOp op) {
1380 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1381 emitAttribute(port.getDirection());
1383 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
1386 auto *mem = port.getMemory().getDefiningOp();
1387 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1388 ps << legalize(seqMem.getNameAttr());
1390 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1394 emitExpression(op.getIndex());
1398 emitExpression(op.getClock());
1400 emitLocationAndNewLine(op);
1403void Emitter::emitStatement(DomainDefineOp op) {
1407 if (isa_and_nonnull<DomainCreateAnonOp>(op.getSrc().getDefiningOp()))
1411 emitAssignLike([&]() { emitExpression(op.getDest()); },
1412 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1414 emitLocationAndNewLine(op);
1417void Emitter::emitStatement(RefDefineOp op) {
1419 emitAssignLike([&]() { emitExpression(op.getDest()); },
1420 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1422 emitLocationAndNewLine(op);
1425void Emitter::emitStatement(RefForceOp op) {
1426 emitStatementFunctionOp(
PPExtString(
"force"), op);
1429void Emitter::emitStatement(RefForceInitialOp op) {
1431 auto constantPredicate =
1432 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1433 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1436 emitExpression(op.getPredicate());
1437 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1439 ps <<
"force_initial(";
1441 interleaveComma({op.getDest(), op.getSrc()});
1446 emitLocationAndNewLine(op);
1449void Emitter::emitStatement(RefReleaseOp op) {
1450 emitStatementFunctionOp(
PPExtString(
"release"), op);
1453void Emitter::emitStatement(RefReleaseInitialOp op) {
1455 auto constantPredicate =
1456 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1457 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1460 emitExpression(op.getPredicate());
1461 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1463 ps <<
"release_initial(";
1464 emitExpression(op.getDest());
1468 emitLocationAndNewLine(op);
1471void Emitter::emitStatement(LayerBlockOp op) {
1472 if (failed(requireVersion(
FIRVersion(3, 3, 0), op,
"layers")))
1475 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1476 emitLocationAndNewLine(op);
1477 auto *body = op.getBody();
1478 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1481void Emitter::emitStatement(InvalidValueOp op) {
1484 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1485 return use.getOperandNumber() == 1 &&
1486 isa<ConnectOp, MatchingConnectOp>(use.getOwner());
1492 auto name = circuitNamespace.newName(
"_invalid");
1493 addValueName(op, name);
1495 emitType(op.getType());
1496 emitLocationAndNewLine(op);
1502 emitLocationAndNewLine(op);
1505void Emitter::emitStatement(GenericIntrinsicOp op) {
1506 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"generic intrinsics")))
1510 emitGenericIntrinsic(op);
1513 auto name = circuitNamespace.newName(
"_gen_int");
1514 addValueName(op.getResult(), name);
1515 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(name); },
1516 [&]() { emitGenericIntrinsic(op); });
1518 emitLocationAndNewLine(op);
1521void Emitter::emitStatement(DomainCreateAnonOp op) {
1525void Emitter::emitStatement(DomainCreateOp op) {
1529 auto name = legalize(op.getNameAttr());
1530 addValueName(op.getResult(), name);
1535 auto fieldValues = op.getFieldValues();
1536 if (fieldValues.empty())
1539 ps <<
"(" << PP::ibox0;
1540 interleaveComma(fieldValues, [&](
auto value) { emitExpression(value); });
1541 ps <<
")" << PP::end;
1544 emitLocationAndNewLine(op);
1547void Emitter::emitExpression(Value value) {
1550 if (
auto name = lookupEmittedName(value)) {
1556 auto op = value.getDefiningOp();
1557 assert(op &&
"value must either be a block arg or the result of an op");
1558 TypeSwitch<Operation *>(op)
1561 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1562 OpenSubfieldOp, OpenSubindexOp, DomainSubfieldOp,
1564 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1565 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1566 EQPrimOp, NEQPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1568 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsResetPrimOp,
1569 AsClockPrimOp, CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp,
1572 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1573 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1574 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1575 UnresolvedPathOp, GenericIntrinsicOp, CatPrimOp, UnsafeDomainCastOp,
1576 UnknownValueOp, StringConcatOp, PropEqOp, BoolAndOp, BoolOrOp,
1579 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp,
1581 TimeOp>([&](
auto op) {
1582 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1584 .Default([&](
auto op) {
1585 emitOpError(op,
"not supported as expression");
1586 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1591void Emitter::emitExpression(ConstantOp op) {
1593 emitType(op.getType(),
false);
1600void Emitter::emitExpression(SpecialConstantOp op) {
1601 auto emitInner = [&]() {
1608 .
Case<ClockType>([&](
auto type) {
1613 .Case<ResetType>([&](
auto type) { emitInner(); })
1614 .Case<AsyncResetType>([&](
auto type) {
1615 ps <<
"asAsyncReset(";
1622void Emitter::emitExpression(SubfieldOp op) {
1623 BundleType type = op.getInput().getType();
1624 emitExpression(op.getInput());
1625 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1629void Emitter::emitExpression(SubindexOp op) {
1630 emitExpression(op.getInput());
1637void Emitter::emitExpression(SubaccessOp op) {
1638 emitExpression(op.getInput());
1640 emitExpression(op.getIndex());
1644void Emitter::emitExpression(OpenSubfieldOp op) {
1645 auto type = op.getInput().getType();
1646 emitExpression(op.getInput());
1647 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1651void Emitter::emitExpression(DomainSubfieldOp op) {
1652 emitExpression(op.getInput());
1653 ps <<
"." << legalize(op.getFieldName());
1656void Emitter::emitExpression(OpenSubindexOp op) {
1657 emitExpression(op.getInput());
1663void Emitter::emitExpression(RefSendOp op) {
1665 emitExpression(op.getBase());
1669void Emitter::emitExpression(RefResolveOp op) {
1671 emitExpression(op.getRef());
1675void Emitter::emitExpression(RefSubOp op) {
1676 emitExpression(op.getInput());
1678 .
Case<FVectorType>([&](
auto type) {
1684 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1687void Emitter::emitExpression(RWProbeOp op) {
1691 auto target = symInfos->get().irn.lookup(op.getTarget());
1693 if (target.isPort()) {
1694 auto mod = cast<FModuleOp>(target.getOp());
1695 auto port = target.getPort();
1696 base = mod.getArgument(port);
1698 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1701 emitExpression(base);
1704 auto fieldID = target.getField();
1705 auto type = base.getType();
1708 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1709 auto index = vecTy.getIndexForFieldID(fieldID);
1713 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1715 fieldID = subfieldID;
1717 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1718 auto index = bundleTy.getIndexForFieldID(fieldID);
1719 ps <<
"." << bundleTy.getElementName(index);
1720 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1722 fieldID = subfieldID;
1728void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1730void Emitter::emitExpression(UninferredResetCastOp op) {
1731 emitExpression(op.getInput());
1734void Emitter::emitExpression(FIntegerConstantOp op) {
1735 if (failed(requireVersion(
FIRVersion(3, 1, 0), op,
"Integers")))
1742void Emitter::emitExpression(BoolConstantOp op) {
1743 if (failed(requireVersion({6, 0, 0}, op,
"Bools")))
1745 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1748void Emitter::emitExpression(DoubleConstantOp op) {
1749 if (failed(requireVersion({6, 0, 0}, op,
"Doubles")))
1756 SmallString<16> str;
1757 op.getValueAttr().getValue().toString(str);
1762void Emitter::emitExpression(StringConstantOp op) {
1763 if (failed(requireVersion(
FIRVersion(3, 1, 0), op,
"Strings")))
1770void Emitter::emitExpression(ListCreateOp op) {
1771 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"Lists")))
1773 return emitLiteralExpression(op.getType(), op.getElements());
1776void Emitter::emitExpression(UnresolvedPathOp op) {
1777 if (failed(requireVersion({6, 0, 0}, op,
"Paths")))
1784void Emitter::emitExpression(GenericIntrinsicOp op) {
1785 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"generic intrinsics")))
1787 emitGenericIntrinsic(op);
1790void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1792void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1793 ArrayRef<uint32_t> attrs) {
1794 ps << mnemonic <<
"(" << PP::ibox0;
1795 interleaveComma(op->getOperands());
1796 if (!op->getOperands().empty() && !attrs.empty())
1797 ps <<
"," << PP::space;
1798 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1799 ps <<
")" << PP::end;
1802void Emitter::emitExpression(CatPrimOp op) {
1803 size_t numOperands = op.getNumOperands();
1804 switch (numOperands) {
1807 emitType(op.getType(),
false);
1811 auto operand = op->getOperand(0);
1813 if (isa<UIntType>(operand.getType()))
1814 return emitExpression(operand);
1817 ps <<
"cat(" << PP::ibox0;
1818 emitExpression(op->getOperand(0));
1819 ps <<
"," << PP::space <<
"SInt<0>(0))" << PP::end;
1825 for (
size_t i = 0; i < numOperands - 1; ++i) {
1826 ps <<
"cat(" << PP::ibox0;
1827 emitExpression(op->getOperand(i));
1828 ps <<
"," << PP::space;
1831 emitExpression(op->getOperand(numOperands - 1));
1832 for (
size_t i = 0; i < numOperands - 1; ++i)
1833 ps <<
")" << PP::end;
1838void Emitter::emitExpression(UnsafeDomainCastOp op) {
1839 if (failed(requireVersion(
nextFIRVersion, op,
"unsafe_domain_cast")))
1841 ps <<
"unsafe_domain_cast(" << PP::ibox0;
1842 interleaveComma(op.getOperands(),
1843 [&](Value operand) { emitExpression(operand); });
1844 ps <<
")" << PP::end;
1847void Emitter::emitExpression(UnknownValueOp op) {
1849 requireVersion(
nextFIRVersion, op,
"unknown property expressions")))
1852 emitType(op.getType());
1856void Emitter::emitAttribute(MemDirAttr attr) {
1858 case MemDirAttr::Infer:
1861 case MemDirAttr::Read:
1864 case MemDirAttr::Write:
1867 case MemDirAttr::ReadWrite:
1873void Emitter::emitAttribute(RUWBehaviorAttr attr) {
1874 switch (attr.getValue()) {
1875 case RUWBehavior::Undefined:
1878 case RUWBehavior::Old:
1881 case RUWBehavior::New:
1888void Emitter::emitType(Type type,
bool includeConst) {
1889 if (includeConst &&
isConst(type))
1891 auto emitWidth = [&](std::optional<int32_t> width) {
1900 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1901 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1902 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1903 .Case<UIntType>([&](
auto type) {
1905 emitWidth(type.getWidth());
1907 .Case<SIntType>([&](
auto type) {
1909 emitWidth(type.getWidth());
1911 .Case<AnalogType>([&](
auto type) {
1913 emitWidth(type.getWidth());
1915 .Case<OpenBundleType, BundleType>([&](
auto type) {
1917 if (!type.getElements().empty())
1919 bool anyEmitted =
false;
1921 for (
auto &element : type.getElements()) {
1923 ps <<
"," << PP::space;
1927 ps << legalize(element.name);
1928 emitTypeWithColon(element.type);
1937 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1938 emitType(type.getElementType());
1943 .Case<RefType>([&](RefType type) {
1944 if (type.getForceable())
1947 ps.
cbox(2, IndentStyle::Block);
1949 emitType(type.getType());
1950 if (
auto layer = type.getLayer()) {
1953 emitSymbol(type.getLayer());
1958 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1959 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1960 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1961 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1962 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1963 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1964 .Case<ListType>([&](ListType type) {
1966 emitType(type.getElementType());
1969 .Case<DomainType>([&](DomainType type) {
1970 ps <<
"Domain of " <<
PPExtString(type.getName().getValue());
1972 .Default([&](
auto type) {
1973 llvm_unreachable(
"all types should be implemented");
1977void Emitter::emitDomains(Attribute attr, ArrayRef<PortInfo> ports) {
1980 auto domains = cast<ArrayAttr>(attr);
1981 if (domains.empty())
1985 interleaveComma(domains, [&](Attribute attr) {
1986 ps.
addAsString(ports[cast<IntegerAttr>(attr).getUInt()].name.getValue());
1994void Emitter::emitLocation(Location loc) {
1996 ps << PP::neverbreak;
1998 dyn_cast_or_null<FileLineColLoc, LocationAttr>(LocationAttr(loc))) {
1999 ps <<
" @[" << fileLoc.getFilename().getValue();
2000 if (
auto line = fileLoc.getLine()) {
2003 if (
auto col = fileLoc.getColumn()) {
2020 std::optional<size_t> targetLineLength,
2023 return module.emitError("--firrtl-version ")
2024 << version << " is below the minimum supported "
2025 << "version " << minimumFIRVersion;
2026 Emitter emitter(os, version,
2027 targetLineLength.value_or(defaultTargetLineLength));
2028 for (
auto &op : *
module.getBody()) {
2029 if (auto circuitOp = dyn_cast<CircuitOp>(op))
2030 emitter.emitCircuit(circuitOp);
2032 return emitter.finalize();
2037 "target-line-length",
2038 llvm::cl::desc(
"Target line length for emitted .fir; 0 disables line "
2040 llvm::cl::value_desc(
"number of chars"),
2041 llvm::cl::init(defaultTargetLineLength));
2044 llvm::cl::desc(
"FIRRTL version to target (e.g. \"3.0.0\"). "
2045 "Defaults to the latest supported version."),
2046 llvm::cl::value_desc(
"major.minor.patch"), llvm::cl::init(
""));
2047 static mlir::TranslateFromMLIRRegistration toFIR(
2048 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
2049 [](ModuleOp module, llvm::raw_ostream &os) -> mlir::LogicalResult {
2051 if (!firrtlVersionStr.empty()) {
2052 auto ver = FIRVersion::fromString(firrtlVersionStr);
2054 return module.emitError(
"invalid --firrtl-version: '")
2056 <<
"', expected format 'major.minor.patch'";
2059 return exportFIRFile(module, os, targetLineLength, version);
2061 [](mlir::DialectRegistry ®istry) {
2062 registry.insert<chirrtl::CHIRRTLDialect>();
2063 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.
static constexpr uint32_t kInfinity
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 nextFIRVersion(7, 0, 0)
The next version of FIRRTL that is not yet released.
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...
constexpr FIRVersion missingSpecFIRVersion
A marker for parser features that are currently missing from the spec.
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
constexpr FIRVersion minimumFIRVersion(2, 0, 0)
The current minimum version of FIRRTL that the parser supports.
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.