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, Operation *op);
69 void emitKnownLayers(ArrayRef<Attribute> layers, Operation *op);
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(PropertyAssertOp op);
96 void emitStatement(PropAssignOp op);
97 void emitStatement(InstanceOp op);
98 void emitStatement(InstanceChoiceOp op);
99 void emitStatement(AttachOp op);
100 void emitStatement(MemOp op);
101 void emitStatement(InvalidValueOp op);
102 void emitStatement(CombMemOp op);
103 void emitStatement(SeqMemOp op);
104 void emitStatement(MemoryPortOp op);
105 void emitStatement(MemoryDebugPortOp op);
106 void emitStatement(MemoryPortAccessOp op);
107 void emitStatement(DomainDefineOp op);
108 void emitStatement(RefDefineOp op);
109 void emitStatement(RefForceOp op);
110 void emitStatement(RefForceInitialOp op);
111 void emitStatement(RefReleaseOp op);
112 void emitStatement(RefReleaseInitialOp op);
113 void emitStatement(LayerBlockOp op);
114 void emitStatement(GenericIntrinsicOp op);
115 void emitStatement(DomainCreateAnonOp op);
116 void emitStatement(DomainCreateOp op);
119 void emitVerifStatement(T op, StringRef mnemonic);
120 void emitStatement(AssertOp op) { emitVerifStatement(op,
"assert"); }
121 void emitStatement(AssumeOp op) { emitVerifStatement(op,
"assume"); }
122 void emitStatement(CoverOp op) { emitVerifStatement(op,
"cover"); }
125 void emitExpression(Value value);
126 void emitExpression(ConstantOp op);
127 void emitExpression(SpecialConstantOp op);
128 void emitExpression(SubfieldOp op);
129 void emitExpression(SubindexOp op);
130 void emitExpression(SubaccessOp op);
131 void emitExpression(OpenSubfieldOp op);
132 void emitExpression(DomainSubfieldOp op);
133 void emitExpression(OpenSubindexOp op);
134 void emitExpression(RefResolveOp op);
135 void emitExpression(RefSendOp op);
136 void emitExpression(RefSubOp op);
137 void emitExpression(RWProbeOp op);
138 void emitExpression(RefCastOp op);
139 void emitExpression(UninferredResetCastOp op);
140 void emitExpression(ConstCastOp op);
141 void emitExpression(StringConstantOp op);
142 void emitExpression(FIntegerConstantOp op);
143 void emitExpression(BoolConstantOp op);
144 void emitExpression(DoubleConstantOp op);
145 void emitExpression(ListCreateOp op);
146 void emitExpression(UnresolvedPathOp op);
147 void emitExpression(GenericIntrinsicOp op);
148 void emitExpression(CatPrimOp op);
149 void emitExpression(UnsafeDomainCastOp op);
150 void emitExpression(UnknownValueOp op);
152 void emitPrimExpr(StringRef mnemonic, Operation *op,
153 ArrayRef<uint32_t> attrs = {});
155 void emitExpression(BitsPrimOp op) {
156 emitPrimExpr(
"bits", op, {op.getHi(), op.getLo()});
158 void emitExpression(HeadPrimOp op) {
159 emitPrimExpr(
"head", op, op.getAmount());
161 void emitExpression(TailPrimOp op) {
162 emitPrimExpr(
"tail", op, op.getAmount());
164 void emitExpression(PadPrimOp op) { emitPrimExpr(
"pad", op, op.getAmount()); }
165 void emitExpression(ShlPrimOp op) { emitPrimExpr(
"shl", op, op.getAmount()); }
166 void emitExpression(ShrPrimOp op) { emitPrimExpr(
"shr", op, op.getAmount()); }
168 void emitExpression(TimeOp op) {}
171#define HANDLE(OPTYPE, MNEMONIC) \
172 void emitExpression(OPTYPE op) { emitPrimExpr(MNEMONIC, op); }
187 HANDLE(DShlPrimOp,
"dshl");
188 HANDLE(DShlwPrimOp,
"dshlw");
189 HANDLE(DShrPrimOp,
"dshr");
191 HANDLE(AsSIntPrimOp,
"asSInt");
192 HANDLE(AsUIntPrimOp,
"asUInt");
193 HANDLE(AsAsyncResetPrimOp,
"asAsyncReset");
194 HANDLE(AsResetPrimOp,
"asReset");
195 HANDLE(AsClockPrimOp,
"asClock");
199 HANDLE(AndRPrimOp,
"andr");
201 HANDLE(XorRPrimOp,
"xorr");
202 HANDLE(StringConcatOp,
"string_concat");
205 void emitExpression(PropEqOp op) {
208 emitPrimExpr(
"prop_eq", op);
212 void emitAttribute(MemDirAttr attr);
213 void emitAttribute(RUWBehaviorAttr attr);
216 void emitType(Type type,
bool includeConst =
true);
217 void emitTypeWithColon(Type type) {
218 ps << PP::space <<
":" << PP::nbsp;
223 void emitDomains(Attribute attr, ArrayRef<PortInfo> ports);
226 void emitLocation(Location loc);
227 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
228 template <
typename... Args>
229 void emitLocationAndNewLine(Args... args) {
232 ps << PP::neverbreak;
233 emitLocation(args...);
237 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
238 llvm::function_ref<
void()> emitRHS,
240 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
242 ps.scopedBox(PP::ibox2, [&]() {
244 ps << *wordBeforeLHS << PP::space;
248 ps << PP::space << syntax << PP::nbsp;
250 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
255 void emitSubExprIBox2(Value v) {
256 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
261 template <
typename Container,
typename EachFn>
262 void interleaveComma(
const Container &c, EachFn eachFn) {
263 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
268 void interleaveComma(ValueRange ops) {
269 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
272 void emitStatementFunctionOp(
PPExtString name, Operation *op) {
275 ps.scopedBox(PP::ibox0, [&]() {
276 interleaveComma(op->getOperands());
279 emitLocationAndNewLine(op);
282 template <
typename EachFn,
typename Range>
283 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
286 ps.scopedBox(PP::ibox0, [&]() {
287 interleaveComma(r, eachFn);
292 void emitLiteralExpression(Type type, ValueRange values) {
293 return emitLiteralExpression(type, values,
294 [&](Value v) { emitSubExprIBox2(v); });
298 void emitSymbol(SymbolRefAttr symbol) {
299 ps.ibox(2, IndentStyle::Block);
300 ps << symbol.getRootReference();
301 for (
auto nested : symbol.getNestedReferences()) {
304 ps << nested.getAttr();
311 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
312 encounteredError =
true;
313 return op->emitError(message);
317 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
318 encounteredError =
true;
319 return op->emitOpError(message);
323 LogicalResult requireVersion(
FIRVersion minVersion, Operation *op,
325 if (version >= minVersion)
328 return emitOpError(op, feature +
" requires FIRRTL ") << minVersion;
333 std::optional<StringRef> lookupEmittedName(Value value) {
334 auto it = valueNames.find(value);
335 if (it != valueNames.end())
342 void emitPendingNewlineIfNeeded() {
343 if (pendingNewline) {
344 pendingNewline =
false;
348 void setPendingNewline() {
350 pendingNewline =
true;
353 void startStatement() { emitPendingNewlineIfNeeded(); }
371 bool pendingNewline =
false;
374 bool encounteredError =
false;
379 DenseMap<Value, StringRef> valueNames;
380 StringSet<> valueNamesStorage;
384 StringAttr legalize(StringAttr attr) {
385 StringRef str = attr.getValue();
386 if (str.empty() || !
isdigit(str.front()))
388 return StringAttr::get(attr.getContext(),
"`" + Twine(attr) +
"`");
391 void addValueName(Value value, StringAttr attr) {
392 valueNames.insert({value, attr.getValue()});
394 void addValueName(Value value, StringRef str) {
395 auto it = valueNamesStorage.insert(str);
396 valueNames.insert({value, it.first->getKey()});
398 void addForceable(Forceable op, StringAttr attr) {
399 addValueName(op.getData(), attr);
400 if (op.isForceable()) {
401 SmallString<32> rwName;
402 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
403 addValueName(op.getDataRef(), rwName);
412 SymbolTable symbolTable;
415 SymInfos(Operation *op) : symbolTable(op), istc(op) {}
417 std::optional<std::reference_wrapper<SymInfos>> symInfos;
424LogicalResult Emitter::finalize() {
return failure(encounteredError); }
427void Emitter::emitCircuit(CircuitOp op) {
428 circuitNamespace.add(op);
429 SymInfos circuitSymInfos(op);
430 symInfos = circuitSymInfos;
432 ps <<
"FIRRTL version ";
439 ps <<
"circuit " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
443 if (encounteredError)
445 TypeSwitch<Operation *>(&bodyOp)
446 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](
auto op) {
450 .Case<DomainOp, LayerOp, OptionOp, FormalOp, SimulationOp>(
451 [&](
auto op) { emitDeclaration(op); })
452 .Default([&](
auto op) {
453 emitOpError(op,
"not supported for emission inside circuit");
457 circuitNamespace.clear();
458 symInfos = std::nullopt;
461void Emitter::emitEnabledLayers(ArrayRef<Attribute> layers, Operation *op) {
464 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"enabled layers")))
466 for (
auto layer : layers) {
468 ps.
cbox(2, IndentStyle::Block);
469 ps <<
"enablelayer" << PP::space;
470 emitSymbol(cast<SymbolRefAttr>(layer));
475void Emitter::emitKnownLayers(ArrayRef<Attribute> layers, Operation *op) {
480 for (
auto layer : layers) {
482 ps.
cbox(2, IndentStyle::Block);
483 ps <<
"knownlayer" << PP::space;
484 emitSymbol(cast<SymbolRefAttr>(layer));
489void Emitter::emitRequirements(ArrayRef<Attribute> requirements) {
490 if (requirements.empty())
493 ps.
cbox(2, IndentStyle::Block);
494 ps <<
"requires" << PP::space;
495 llvm::interleaveComma(requirements, ps, [&](Attribute req) {
501void Emitter::emitParamAssign(ParamDeclAttr param, Operation *op,
502 std::optional<PPExtString> wordBeforeLHS) {
504 ps << *wordBeforeLHS << PP::nbsp;
506 ps <<
PPExtString(param.getName().strref()) << PP::nbsp <<
"=" << PP::nbsp;
507 emitParamValue(param.getValue(), op);
510void Emitter::emitParamValue(Attribute value, Operation *op) {
511 TypeSwitch<Attribute>(value)
512 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
513 .Case<FloatAttr>([&](
auto attr) {
515 attr.getValue().toString(str);
520 .Case<ArrayAttr>([&](
auto attr) {
523 interleaveComma(attr.getValue(),
524 [&](
auto element) { emitParamValue(element, op); });
528 .Case<DictionaryAttr>([&](
auto attr) {
531 interleaveComma(attr.getValue(), [&](
auto field) {
532 ps << PPExtString(field.getName()) << PP::nbsp <<
"=" << PP::nbsp;
533 emitParamValue(field.getValue(), op);
538 .Default([&](
auto attr) {
539 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
540 ps <<
"<unsupported-attr ";
546void Emitter::emitGenericIntrinsic(GenericIntrinsicOp op) {
550 ps << op.getIntrinsic();
552 auto params = op.getParameters();
553 if (!params.empty()) {
555 ps.scopedBox(PP::ibox0, [&]() {
557 params.getAsRange<ParamDeclAttr>(),
558 [&](ParamDeclAttr param) { emitParamAssign(param, op); });
563 if (op.getNumResults() != 0)
564 emitTypeWithColon(op.getResult().getType());
566 if (op.getNumOperands() != 0) {
567 ps <<
"," << PP::space;
568 ps.
scopedBox(PP::ibox0, [&]() { interleaveComma(op->getOperands()); });
575void Emitter::emitModule(FModuleOp op) {
577 ps.
cbox(4, IndentStyle::Block);
578 if (op.isPublic() &&
FIRVersion(3, 3, 0) <= version)
579 ps <<
"public" << PP::nbsp;
580 ps <<
"module " <<
PPExtString(legalize(op.getNameAttr()));
581 emitEnabledLayers(op.getLayers(), op);
582 ps << PP::nbsp <<
":" << PP::end;
589 auto ports = op.getPorts();
590 emitModulePorts(ports, op.getArguments());
591 if (!ports.empty() && !op.getBodyBlock()->empty())
595 emitStatementsInBlock(*op.getBodyBlock());
598 valueNamesStorage.clear();
602void Emitter::emitModule(FExtModuleOp op) {
604 ps.
cbox(4, IndentStyle::Block);
605 ps <<
"extmodule " <<
PPExtString(legalize(op.getNameAttr()));
606 emitKnownLayers(op.getKnownLayers(), op);
607 emitEnabledLayers(op.getLayers(), op);
608 if (
auto reqs = op.getExternalRequirements())
609 emitRequirements(reqs.getValue());
610 ps << PP::nbsp <<
":" << PP::end;
617 auto ports = op.getPorts();
618 emitModulePorts(ports);
621 if (op.getDefname() && !op.getDefname()->empty()) {
623 ps <<
"defname = " <<
PPExtString(*op.getDefname());
628 emitModuleParameters(op, op.getParameters());
633void Emitter::emitModule(FIntModuleOp op) {
635 emitOpError(op,
"intrinsic modules were removed in FIRRTL 4.0.0");
639 ps.
cbox(4, IndentStyle::Block);
640 ps <<
"intmodule " <<
PPExtString(legalize(op.getNameAttr()));
641 emitEnabledLayers(op.getLayers(), op);
642 ps << PP::nbsp <<
":" << PP::end;
649 auto ports = op.getPorts();
650 emitModulePorts(ports);
653 ps <<
"intrinsic = " <<
PPExtString(op.getIntrinsic());
657 emitModuleParameters(op, op.getParameters());
664void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
665 Block::BlockArgListType arguments) {
667 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
669 const auto &port = ports[i];
670 ps << (port.direction == Direction::In ?
"input " :
"output ");
671 auto legalName = legalize(port.name);
672 if (!arguments.empty())
673 addValueName(arguments[i], legalName);
676 emitDomains(port.domains, ports);
677 emitLocation(ports[i].loc);
682void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
683 for (
auto param : parameters.getAsRange<ParamDeclAttr>()) {
685 emitParamAssign(param, op,
PPExtString(
"parameter"));
690void Emitter::emitDeclaration(DomainOp op) {
694 ps <<
"domain " <<
PPExtString(op.getSymName()) <<
" :";
695 emitLocationAndNewLine(op);
697 for (
auto attr : op.getFields()) {
698 auto fieldAttr = cast<DomainFieldAttr>(attr);
699 ps << PP::newline <<
PPExtString(fieldAttr.getName()) <<
" : ";
700 emitType(fieldAttr.getType());
706void Emitter::emitDeclaration(LayerOp op) {
707 if (failed(requireVersion(
FIRVersion(3, 3, 0), op,
"layers")))
709 if (op.getConvention() == LayerConvention::Inline &&
710 failed(requireVersion(
FIRVersion(4, 1, 0), op,
"inline layers")))
713 ps <<
"layer " <<
PPExtString(op.getSymName()) <<
", "
714 <<
PPExtString(stringifyLayerConvention(op.getConvention()));
716 if (
auto outputFile = op->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
722 emitLocationAndNewLine(op);
724 for (
auto &bodyOp : op.getBody().getOps()) {
725 TypeSwitch<Operation *>(&bodyOp)
726 .Case<LayerOp>([&](
auto op) { emitDeclaration(op); })
727 .Default([&](
auto op) {
729 "not supported for emission inside layer definition");
736void Emitter::emitDeclaration(OptionOp op) {
740 ps <<
"option " <<
PPExtString(legalize(op.getSymNameAttr())) <<
" :";
743 for (
auto caseOp : op.getBody().getOps<OptionCaseOp>()) {
745 ps <<
PPExtString(legalize(caseOp.getSymNameAttr()));
746 emitLocation(caseOp);
749 ps << PP::newline << PP::newline;
753void Emitter::emitDeclaration(FormalOp op) {
754 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"formal tests")))
756 emitFormalLike(op,
"formal", op.getSymNameAttr(),
757 op.getModuleNameAttr().getAttr(), op.getParameters());
761void Emitter::emitDeclaration(SimulationOp op) {
762 if (failed(requireVersion(
nextFIRVersion, op,
"simulation tests")))
764 emitFormalLike(op,
"simulation", op.getSymNameAttr(),
765 op.getModuleNameAttr().getAttr(), op.getParameters());
769void Emitter::emitFormalLike(Operation *op, StringRef keyword,
770 StringAttr symName, StringAttr moduleName,
771 DictionaryAttr params) {
773 ps.
cbox(4, IndentStyle::Block);
774 ps << keyword <<
" " <<
PPExtString(legalize(symName));
776 ps << PP::nbsp <<
":" << PP::end;
781 for (
auto param : params) {
783 ps <<
PPExtString(param.getName()) << PP::nbsp <<
"=" << PP::nbsp;
784 emitParamValue(param.getValue(), op);
798 return (
isExpression(op) && !isa<InvalidValueOp>(op)) ||
799 (isa<GenericIntrinsicOp>(op) && op->hasOneUse() &&
803void Emitter::emitStatementsInBlock(Block &block) {
804 for (
auto &bodyOp : block) {
805 if (encounteredError)
809 TypeSwitch<Operation *>(&bodyOp)
810 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
811 PrintFOp, FPrintFOp, FFlushOp, AssertOp, AssumeOp, CoverOp,
812 ConnectOp, MatchingConnectOp, PropertyAssertOp, PropAssignOp,
813 InstanceOp, InstanceChoiceOp, AttachOp, MemOp, InvalidValueOp,
814 SeqMemOp, CombMemOp, MemoryPortOp, MemoryDebugPortOp,
815 MemoryPortAccessOp, DomainDefineOp, RefDefineOp, RefForceOp,
816 RefForceInitialOp, RefReleaseOp, RefReleaseInitialOp,
817 LayerBlockOp, GenericIntrinsicOp, DomainCreateAnonOp,
818 DomainCreateOp>([&](
auto op) { emitStatement(op); })
819 .Default([&](
auto op) {
821 ps <<
"// operation " <<
PPExtString(op->getName().getStringRef());
823 emitOpError(op,
"not supported as statement");
828void Emitter::emitStatement(WhenOp op) {
831 emitExpression(op.getCondition());
833 emitLocationAndNewLine(op);
834 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
836 if (!op.hasElseRegion())
843 auto &elseBlock = op.getElseBlock();
844 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
845 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
846 emitStatement(whenOp);
853 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
856void Emitter::emitStatement(WireOp op) {
857 auto legalName = legalize(op.getNameAttr());
858 addForceable(op, legalName);
862 emitTypeWithColon(op.getResult().getType());
865 if (!op.getDomains().empty()) {
866 ps << PP::space <<
"domains" << PP::space <<
"[";
868 llvm::interleaveComma(op.getDomains(), ps, [&](Value domain) {
869 auto name = lookupEmittedName(domain);
870 assert(name &&
"domain value must have a name");
871 ps << PPExtString(*name);
877 emitLocationAndNewLine(op);
880void Emitter::emitStatement(RegOp op) {
881 auto legalName = legalize(op.getNameAttr());
882 addForceable(op, legalName);
886 emitTypeWithColon(op.getResult().getType());
887 ps <<
"," << PP::space;
888 emitExpression(op.getClockVal());
890 emitLocationAndNewLine(op);
893void Emitter::emitStatement(RegResetOp op) {
894 auto legalName = legalize(op.getNameAttr());
895 addForceable(op, legalName);
899 ps <<
"regreset " << legalName;
900 emitTypeWithColon(op.getResult().getType());
901 ps <<
"," << PP::space;
902 emitExpression(op.getClockVal());
903 ps <<
"," << PP::space;
904 emitExpression(op.getResetSignal());
905 ps <<
"," << PP::space;
906 emitExpression(op.getResetValue());
910 ps <<
"reg " << legalName;
911 emitTypeWithColon(op.getResult().getType());
912 ps <<
"," << PP::space;
913 emitExpression(op.getClockVal());
914 ps << PP::space <<
"with :";
916 ps << PP::neverbreak;
919 ps <<
"reset => (" << PP::ibox0;
920 emitExpression(op.getResetSignal());
921 ps <<
"," << PP::space;
922 emitExpression(op.getResetValue());
923 ps <<
")" << PP::end;
926 emitLocationAndNewLine(op);
929void Emitter::emitStatement(NodeOp op) {
930 auto legalName = legalize(op.getNameAttr());
931 addForceable(op, legalName);
933 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(legalName); },
934 [&]() { emitExpression(op.getInput()); });
935 emitLocationAndNewLine(op);
938void Emitter::emitStatement(StopOp op) {
941 ps <<
"stop(" << PP::ibox0;
942 emitExpression(op.getClock());
943 ps <<
"," << PP::space;
944 emitExpression(op.getCond());
945 ps <<
"," << PP::space;
947 ps <<
")" << PP::end;
948 if (!op.getName().empty()) {
949 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
952 emitLocationAndNewLine(op);
955void Emitter::emitStatement(SkipOp op) {
958 emitLocationAndNewLine(op);
961void Emitter::emitFormatString(Operation *op, StringRef origFormatString,
962 OperandRange substitutionOperands,
963 llvm::SmallVectorImpl<Value> &substitutions) {
972 SmallString<64> formatString;
973 for (
size_t i = 0, e = origFormatString.size(), opIdx = 0; i != e; ++i) {
974 auto c = origFormatString[i];
977 formatString.push_back(c);
980 SmallString<6> width;
981 c = origFormatString[++i];
984 c = origFormatString[++i];
993 formatString.append(width);
996 substitutions.push_back(substitutionOperands[opIdx++]);
999 formatString.push_back(c);
1004 if (origFormatString.slice(i, i + 4) ==
"{{}}") {
1005 formatString.append(
"{{");
1006 TypeSwitch<Operation *>(substitutionOperands[opIdx++].getDefiningOp())
1008 [&](
auto time) { formatString.append(
"SimulationTime"); })
1009 .Case<HierarchicalModuleNameOp>([&](
auto time) {
1010 formatString.append(
"HierarchicalModuleName");
1012 .Default([&](
auto) {
1013 emitError(op,
"unsupported fstring substitution type");
1015 formatString.append(
"}}");
1020 formatString.push_back(c);
1026void Emitter::emitStatement(PrintFOp op) {
1029 ps <<
"printf(" << PP::ibox0;
1030 emitExpression(op.getClock());
1031 ps <<
"," << PP::space;
1032 emitExpression(op.getCond());
1033 ps <<
"," << PP::space;
1035 SmallVector<Value, 4> substitutions;
1036 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
1038 for (
auto operand : substitutions) {
1039 ps <<
"," << PP::space;
1040 emitExpression(operand);
1042 ps <<
")" << PP::end;
1043 if (!op.getName().empty()) {
1044 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1047 emitLocationAndNewLine(op);
1050void Emitter::emitStatement(FPrintFOp op) {
1055 ps <<
"fprintf(" << PP::ibox0;
1056 emitExpression(op.getClock());
1057 ps <<
"," << PP::space;
1058 emitExpression(op.getCond());
1059 ps <<
"," << PP::space;
1061 SmallVector<Value, 4> outputFileSubstitutions;
1062 emitFormatString(op, op.getOutputFile(), op.getOutputFileSubstitutions(),
1063 outputFileSubstitutions);
1064 if (!outputFileSubstitutions.empty()) {
1065 ps <<
"," << PP::space;
1066 interleaveComma(outputFileSubstitutions);
1069 ps <<
"," << PP::space;
1070 SmallVector<Value, 4> substitutions;
1071 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
1073 if (!substitutions.empty()) {
1074 ps <<
"," << PP::space;
1075 interleaveComma(substitutions);
1078 ps <<
")" << PP::end;
1079 if (!op.getName().empty()) {
1080 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1083 emitLocationAndNewLine(op);
1086void Emitter::emitStatement(FFlushOp op) {
1091 ps <<
"fflush(" << PP::ibox0;
1092 emitExpression(op.getClock());
1093 ps <<
"," << PP::space;
1094 emitExpression(op.getCond());
1095 if (op.getOutputFileAttr()) {
1096 ps <<
"," << PP::space;
1097 SmallVector<Value, 4> substitutions;
1098 emitFormatString(op, op.getOutputFileAttr(),
1099 op.getOutputFileSubstitutions(), substitutions);
1100 if (!substitutions.empty()) {
1101 ps <<
"," << PP::space;
1102 interleaveComma(substitutions);
1105 ps <<
")" << PP::end;
1107 emitLocationAndNewLine(op);
1111void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
1114 ps << mnemonic <<
"(" << PP::ibox0;
1115 emitExpression(op.getClock());
1116 ps <<
"," << PP::space;
1117 emitExpression(op.getPredicate());
1118 ps <<
"," << PP::space;
1119 emitExpression(op.getEnable());
1120 ps <<
"," << PP::space;
1122 ps <<
")" << PP::end;
1123 if (!op.getName().empty()) {
1124 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1127 emitLocationAndNewLine(op);
1130void Emitter::emitStatement(ConnectOp op) {
1134 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1135 ps <<
"invalidate" << PP::space;
1136 emitExpression(op.getDest());
1138 ps <<
"connect" << PP::space;
1139 emitExpression(op.getDest());
1140 ps <<
"," << PP::space;
1141 emitExpression(op.getSrc());
1145 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1146 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1148 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1151 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1154 emitLocationAndNewLine(op);
1157void Emitter::emitStatement(MatchingConnectOp op) {
1161 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1162 ps <<
"invalidate" << PP::space;
1163 emitExpression(op.getDest());
1165 ps <<
"connect" << PP::space;
1166 emitExpression(op.getDest());
1167 ps <<
"," << PP::space;
1168 emitExpression(op.getSrc());
1172 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1173 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1175 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1178 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1181 emitLocationAndNewLine(op);
1184void Emitter::emitStatement(PropertyAssertOp op) {
1187 ps <<
"propassert" << PP::space;
1188 emitExpression(op.getCondition());
1189 ps <<
"," << PP::space;
1192 emitLocationAndNewLine(op);
1195void Emitter::emitStatement(PropAssignOp op) {
1196 if (failed(requireVersion(
FIRVersion(3, 1, 0), op,
"properties")))
1200 ps <<
"propassign" << PP::space;
1201 interleaveComma(op.getOperands());
1203 emitLocationAndNewLine(op);
1206void Emitter::emitStatement(InstanceOp op) {
1208 auto legalName = legalize(op.getNameAttr());
1210 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
1211 emitLocationAndNewLine(op);
1215 SmallString<16> portName(legalName);
1216 portName.push_back(
'.');
1217 unsigned baseLen = portName.size();
1218 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1219 portName.append(legalize(op.getPortNameAttr(i)));
1220 addValueName(op.getResult(i), portName);
1221 portName.resize(baseLen);
1225void Emitter::emitStatement(InstanceChoiceOp op) {
1227 "option groups/instance choices")))
1230 auto legalName = legalize(op.getNameAttr());
1231 ps <<
"instchoice " <<
PPExtString(legalName) <<
" of "
1232 <<
PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
1233 <<
PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
1236 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
1238 ps <<
PPExtString(legalize(optSym.getLeafReference()));
1243 setPendingNewline();
1245 SmallString<16> portName(legalName);
1246 portName.push_back(
'.');
1247 unsigned baseLen = portName.size();
1248 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1249 portName.append(legalize(op.getPortNameAttr(i)));
1250 addValueName(op.getResult(i), portName);
1251 portName.resize(baseLen);
1255void Emitter::emitStatement(AttachOp op) {
1256 emitStatementFunctionOp(
PPExtString(
"attach"), op);
1259void Emitter::emitStatement(MemOp op) {
1260 auto legalName = legalize(op.getNameAttr());
1261 SmallString<16> portName(legalName);
1262 portName.push_back(
'.');
1263 auto portNameBaseLen = portName.size();
1264 for (
auto result :
llvm::zip(op.getResults(), op.getPortNames())) {
1265 portName.resize(portNameBaseLen);
1266 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
1267 addValueName(std::get<0>(result), portName);
1272 emitLocationAndNewLine(op);
1275 ps <<
"data-type => ";
1276 emitType(op.getDataType());
1281 ps <<
"read-latency => ";
1284 ps <<
"write-latency => ";
1288 SmallString<16> reader, writer, readwriter;
1289 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
1290 auto add = [&](SmallString<16> &to, StringAttr name) {
1293 to.append(name.getValue());
1295 switch (port.second) {
1296 case MemOp::PortKind::Read:
1297 add(reader, legalize(port.first));
1299 case MemOp::PortKind::Write:
1300 add(writer, legalize(port.first));
1302 case MemOp::PortKind::ReadWrite:
1303 add(readwriter, legalize(port.first));
1305 case MemOp::PortKind::Debug:
1306 emitOpError(op,
"has unsupported 'debug' port");
1310 if (!reader.empty())
1311 ps <<
"reader => " << reader << PP::newline;
1312 if (!writer.empty())
1313 ps <<
"writer => " << writer << PP::newline;
1314 if (!readwriter.empty())
1315 ps <<
"readwriter => " << readwriter << PP::newline;
1317 ps <<
"read-under-write => ";
1318 emitAttribute(op.getRuwAttr());
1319 setPendingNewline();
1323void Emitter::emitStatement(SeqMemOp op) {
1326 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
1327 emitTypeWithColon(op.getType());
1328 ps <<
"," << PP::space;
1329 emitAttribute(op.getRuwAttr());
1331 emitLocationAndNewLine(op);
1334void Emitter::emitStatement(CombMemOp op) {
1337 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
1338 emitTypeWithColon(op.getType());
1340 emitLocationAndNewLine(op);
1343void Emitter::emitStatement(MemoryPortOp op) {
1345 addValueName(op.getData(), legalize(op.getNameAttr()));
1348void Emitter::emitStatement(MemoryDebugPortOp op) {
1350 addValueName(op.getData(), legalize(op.getNameAttr()));
1353void Emitter::emitStatement(MemoryPortAccessOp op) {
1357 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1358 emitAttribute(port.getDirection());
1360 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
1363 auto *mem = port.getMemory().getDefiningOp();
1364 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1365 ps << legalize(seqMem.getNameAttr());
1367 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1371 emitExpression(op.getIndex());
1375 emitExpression(op.getClock());
1377 emitLocationAndNewLine(op);
1380void Emitter::emitStatement(DomainDefineOp op) {
1384 if (isa_and_nonnull<DomainCreateAnonOp>(op.getSrc().getDefiningOp()))
1388 emitAssignLike([&]() { emitExpression(op.getDest()); },
1389 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1391 emitLocationAndNewLine(op);
1394void Emitter::emitStatement(RefDefineOp op) {
1396 emitAssignLike([&]() { emitExpression(op.getDest()); },
1397 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1399 emitLocationAndNewLine(op);
1402void Emitter::emitStatement(RefForceOp op) {
1403 emitStatementFunctionOp(
PPExtString(
"force"), op);
1406void Emitter::emitStatement(RefForceInitialOp op) {
1408 auto constantPredicate =
1409 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1410 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1413 emitExpression(op.getPredicate());
1414 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1416 ps <<
"force_initial(";
1418 interleaveComma({op.getDest(), op.getSrc()});
1423 emitLocationAndNewLine(op);
1426void Emitter::emitStatement(RefReleaseOp op) {
1427 emitStatementFunctionOp(
PPExtString(
"release"), op);
1430void Emitter::emitStatement(RefReleaseInitialOp op) {
1432 auto constantPredicate =
1433 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1434 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1437 emitExpression(op.getPredicate());
1438 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1440 ps <<
"release_initial(";
1441 emitExpression(op.getDest());
1445 emitLocationAndNewLine(op);
1448void Emitter::emitStatement(LayerBlockOp op) {
1449 if (failed(requireVersion(
FIRVersion(3, 3, 0), op,
"layers")))
1452 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1453 emitLocationAndNewLine(op);
1454 auto *body = op.getBody();
1455 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1458void Emitter::emitStatement(InvalidValueOp op) {
1461 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1462 return use.getOperandNumber() == 1 &&
1463 isa<ConnectOp, MatchingConnectOp>(use.getOwner());
1469 auto name = circuitNamespace.newName(
"_invalid");
1470 addValueName(op, name);
1472 emitType(op.getType());
1473 emitLocationAndNewLine(op);
1479 emitLocationAndNewLine(op);
1482void Emitter::emitStatement(GenericIntrinsicOp op) {
1483 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"generic intrinsics")))
1487 emitGenericIntrinsic(op);
1490 auto name = circuitNamespace.newName(
"_gen_int");
1491 addValueName(op.getResult(), name);
1492 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(name); },
1493 [&]() { emitGenericIntrinsic(op); });
1495 emitLocationAndNewLine(op);
1498void Emitter::emitStatement(DomainCreateAnonOp op) {
1502void Emitter::emitStatement(DomainCreateOp op) {
1506 auto name = legalize(op.getNameAttr());
1507 addValueName(op.getResult(), name);
1512 auto fieldValues = op.getFieldValues();
1513 if (fieldValues.empty())
1516 ps <<
"(" << PP::ibox0;
1517 interleaveComma(fieldValues, [&](
auto value) { emitExpression(value); });
1518 ps <<
")" << PP::end;
1521 emitLocationAndNewLine(op);
1524void Emitter::emitExpression(Value value) {
1527 if (
auto name = lookupEmittedName(value)) {
1533 auto op = value.getDefiningOp();
1534 assert(op &&
"value must either be a block arg or the result of an op");
1535 TypeSwitch<Operation *>(op)
1538 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1539 OpenSubfieldOp, OpenSubindexOp, DomainSubfieldOp,
1541 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1542 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1543 EQPrimOp, NEQPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1545 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsResetPrimOp,
1546 AsClockPrimOp, CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp,
1549 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1550 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1551 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1552 UnresolvedPathOp, GenericIntrinsicOp, CatPrimOp, UnsafeDomainCastOp,
1553 UnknownValueOp, StringConcatOp, PropEqOp,
1555 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp,
1557 TimeOp>([&](
auto op) {
1558 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1560 .Default([&](
auto op) {
1561 emitOpError(op,
"not supported as expression");
1562 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1567void Emitter::emitExpression(ConstantOp op) {
1569 emitType(op.getType(),
false);
1576void Emitter::emitExpression(SpecialConstantOp op) {
1577 auto emitInner = [&]() {
1584 .
Case<ClockType>([&](
auto type) {
1589 .Case<ResetType>([&](
auto type) { emitInner(); })
1590 .Case<AsyncResetType>([&](
auto type) {
1591 ps <<
"asAsyncReset(";
1598void Emitter::emitExpression(SubfieldOp op) {
1599 BundleType type = op.getInput().getType();
1600 emitExpression(op.getInput());
1601 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1605void Emitter::emitExpression(SubindexOp op) {
1606 emitExpression(op.getInput());
1613void Emitter::emitExpression(SubaccessOp op) {
1614 emitExpression(op.getInput());
1616 emitExpression(op.getIndex());
1620void Emitter::emitExpression(OpenSubfieldOp op) {
1621 auto type = op.getInput().getType();
1622 emitExpression(op.getInput());
1623 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1627void Emitter::emitExpression(DomainSubfieldOp op) {
1628 emitExpression(op.getInput());
1629 ps <<
"." << legalize(op.getFieldName());
1632void Emitter::emitExpression(OpenSubindexOp op) {
1633 emitExpression(op.getInput());
1639void Emitter::emitExpression(RefSendOp op) {
1641 emitExpression(op.getBase());
1645void Emitter::emitExpression(RefResolveOp op) {
1647 emitExpression(op.getRef());
1651void Emitter::emitExpression(RefSubOp op) {
1652 emitExpression(op.getInput());
1654 .
Case<FVectorType>([&](
auto type) {
1660 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1663void Emitter::emitExpression(RWProbeOp op) {
1667 auto target = symInfos->get().irn.lookup(op.getTarget());
1669 if (target.isPort()) {
1670 auto mod = cast<FModuleOp>(target.getOp());
1671 auto port = target.getPort();
1672 base = mod.getArgument(port);
1674 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1677 emitExpression(base);
1680 auto fieldID = target.getField();
1681 auto type = base.getType();
1684 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1685 auto index = vecTy.getIndexForFieldID(fieldID);
1689 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1691 fieldID = subfieldID;
1693 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1694 auto index = bundleTy.getIndexForFieldID(fieldID);
1695 ps <<
"." << bundleTy.getElementName(index);
1696 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1698 fieldID = subfieldID;
1704void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1706void Emitter::emitExpression(UninferredResetCastOp op) {
1707 emitExpression(op.getInput());
1710void Emitter::emitExpression(FIntegerConstantOp op) {
1711 if (failed(requireVersion(
FIRVersion(3, 1, 0), op,
"Integers")))
1718void Emitter::emitExpression(BoolConstantOp op) {
1721 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1724void Emitter::emitExpression(DoubleConstantOp op) {
1732 SmallString<16> str;
1733 op.getValueAttr().getValue().toString(str);
1738void Emitter::emitExpression(StringConstantOp op) {
1739 if (failed(requireVersion(
FIRVersion(3, 1, 0), op,
"Strings")))
1746void Emitter::emitExpression(ListCreateOp op) {
1747 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"Lists")))
1749 return emitLiteralExpression(op.getType(), op.getElements());
1752void Emitter::emitExpression(UnresolvedPathOp op) {
1760void Emitter::emitExpression(GenericIntrinsicOp op) {
1761 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"generic intrinsics")))
1763 emitGenericIntrinsic(op);
1766void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1768void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1769 ArrayRef<uint32_t> attrs) {
1770 ps << mnemonic <<
"(" << PP::ibox0;
1771 interleaveComma(op->getOperands());
1772 if (!op->getOperands().empty() && !attrs.empty())
1773 ps <<
"," << PP::space;
1774 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1775 ps <<
")" << PP::end;
1778void Emitter::emitExpression(CatPrimOp op) {
1779 size_t numOperands = op.getNumOperands();
1780 switch (numOperands) {
1783 emitType(op.getType(),
false);
1787 auto operand = op->getOperand(0);
1789 if (isa<UIntType>(operand.getType()))
1790 return emitExpression(operand);
1793 ps <<
"cat(" << PP::ibox0;
1794 emitExpression(op->getOperand(0));
1795 ps <<
"," << PP::space <<
"SInt<0>(0))" << PP::end;
1801 for (
size_t i = 0; i < numOperands - 1; ++i) {
1802 ps <<
"cat(" << PP::ibox0;
1803 emitExpression(op->getOperand(i));
1804 ps <<
"," << PP::space;
1807 emitExpression(op->getOperand(numOperands - 1));
1808 for (
size_t i = 0; i < numOperands - 1; ++i)
1809 ps <<
")" << PP::end;
1814void Emitter::emitExpression(UnsafeDomainCastOp op) {
1815 if (failed(requireVersion(
nextFIRVersion, op,
"unsafe_domain_cast")))
1817 ps <<
"unsafe_domain_cast(" << PP::ibox0;
1818 interleaveComma(op.getOperands(),
1819 [&](Value operand) { emitExpression(operand); });
1820 ps <<
")" << PP::end;
1823void Emitter::emitExpression(UnknownValueOp op) {
1825 requireVersion(
nextFIRVersion, op,
"unknown property expressions")))
1828 emitType(op.getType());
1832void Emitter::emitAttribute(MemDirAttr attr) {
1834 case MemDirAttr::Infer:
1837 case MemDirAttr::Read:
1840 case MemDirAttr::Write:
1843 case MemDirAttr::ReadWrite:
1849void Emitter::emitAttribute(RUWBehaviorAttr attr) {
1850 switch (attr.getValue()) {
1851 case RUWBehavior::Undefined:
1854 case RUWBehavior::Old:
1857 case RUWBehavior::New:
1864void Emitter::emitType(Type type,
bool includeConst) {
1865 if (includeConst &&
isConst(type))
1867 auto emitWidth = [&](std::optional<int32_t> width) {
1876 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1877 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1878 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1879 .Case<UIntType>([&](
auto type) {
1881 emitWidth(type.getWidth());
1883 .Case<SIntType>([&](
auto type) {
1885 emitWidth(type.getWidth());
1887 .Case<AnalogType>([&](
auto type) {
1889 emitWidth(type.getWidth());
1891 .Case<OpenBundleType, BundleType>([&](
auto type) {
1893 if (!type.getElements().empty())
1895 bool anyEmitted =
false;
1897 for (
auto &element : type.getElements()) {
1899 ps <<
"," << PP::space;
1903 ps << legalize(element.name);
1904 emitTypeWithColon(element.type);
1913 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1914 emitType(type.getElementType());
1919 .Case<RefType>([&](RefType type) {
1920 if (type.getForceable())
1923 ps.
cbox(2, IndentStyle::Block);
1925 emitType(type.getType());
1926 if (
auto layer = type.getLayer()) {
1929 emitSymbol(type.getLayer());
1934 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1935 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1936 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1937 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1938 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1939 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1940 .Case<ListType>([&](ListType type) {
1942 emitType(type.getElementType());
1945 .Case<DomainType>([&](DomainType type) {
1946 ps <<
"Domain of " <<
PPExtString(type.getName().getValue());
1948 .Default([&](
auto type) {
1949 llvm_unreachable(
"all types should be implemented");
1953void Emitter::emitDomains(Attribute attr, ArrayRef<PortInfo> ports) {
1956 auto domains = cast<ArrayAttr>(attr);
1957 if (domains.empty())
1961 interleaveComma(domains, [&](Attribute attr) {
1962 ps.
addAsString(ports[cast<IntegerAttr>(attr).getUInt()].name.getValue());
1970void Emitter::emitLocation(Location loc) {
1972 ps << PP::neverbreak;
1974 dyn_cast_or_null<FileLineColLoc, LocationAttr>(LocationAttr(loc))) {
1975 ps <<
" @[" << fileLoc.getFilename().getValue();
1976 if (
auto line = fileLoc.getLine()) {
1979 if (
auto col = fileLoc.getColumn()) {
1996 std::optional<size_t> targetLineLength,
1999 return module.emitError("--firrtl-version ")
2000 << version << " is below the minimum supported "
2001 << "version " << minimumFIRVersion;
2002 Emitter emitter(os, version,
2003 targetLineLength.value_or(defaultTargetLineLength));
2004 for (
auto &op : *
module.getBody()) {
2005 if (auto circuitOp = dyn_cast<CircuitOp>(op))
2006 emitter.emitCircuit(circuitOp);
2008 return emitter.finalize();
2013 "target-line-length",
2014 llvm::cl::desc(
"Target line length for emitted .fir"),
2015 llvm::cl::value_desc(
"number of chars"),
2016 llvm::cl::init(defaultTargetLineLength));
2019 llvm::cl::desc(
"FIRRTL version to target (e.g. \"3.0.0\"). "
2020 "Defaults to the latest supported version."),
2021 llvm::cl::value_desc(
"major.minor.patch"), llvm::cl::init(
""));
2022 static mlir::TranslateFromMLIRRegistration toFIR(
2023 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
2024 [](ModuleOp module, llvm::raw_ostream &os) -> mlir::LogicalResult {
2026 if (!firrtlVersionStr.empty()) {
2027 auto ver = FIRVersion::fromString(firrtlVersionStr);
2029 return module.emitError(
"invalid --firrtl-version: '")
2031 <<
"', expected format 'major.minor.patch'";
2034 return exportFIRFile(module, os, targetLineLength, version);
2036 [](mlir::DialectRegistry ®istry) {
2037 registry.insert<chirrtl::CHIRRTLDialect>();
2038 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...
constexpr FIRVersion nextFIRVersion(5, 1, 0)
The next version of FIRRTL that is not yet released.
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.