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"
30 using namespace circt;
31 using namespace firrtl;
32 using namespace chirrtl;
33 using namespace pretty;
42 constexpr
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(LayerOp op);
62 void emitDeclaration(OptionOp op);
63 void emitEnabledLayers(ArrayRef<Attribute> layers);
65 void emitParamAssign(ParamDeclAttr param, Operation *op,
66 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
67 void emitGenericIntrinsic(GenericIntrinsicOp op);
70 void emitStatementsInBlock(
Block &block);
71 void emitStatement(WhenOp op);
72 void emitStatement(WireOp op);
73 void emitStatement(RegOp op);
74 void emitStatement(RegResetOp op);
75 void emitStatement(NodeOp op);
76 void emitStatement(StopOp op);
77 void emitStatement(SkipOp op);
78 void emitStatement(PrintFOp op);
79 void emitStatement(ConnectOp op);
80 void emitStatement(StrictConnectOp op);
81 void emitStatement(PropAssignOp op);
82 void emitStatement(InstanceOp op);
83 void emitStatement(InstanceChoiceOp op);
84 void emitStatement(AttachOp op);
85 void emitStatement(MemOp op);
86 void emitStatement(InvalidValueOp op);
87 void emitStatement(CombMemOp op);
88 void emitStatement(SeqMemOp op);
89 void emitStatement(MemoryPortOp op);
90 void emitStatement(MemoryDebugPortOp op);
91 void emitStatement(MemoryPortAccessOp op);
92 void emitStatement(RefDefineOp op);
93 void emitStatement(RefForceOp op);
94 void emitStatement(RefForceInitialOp op);
95 void emitStatement(RefReleaseOp op);
96 void emitStatement(RefReleaseInitialOp op);
97 void emitStatement(LayerBlockOp op);
98 void emitStatement(GenericIntrinsicOp op);
101 void emitVerifStatement(T op, StringRef mnemonic);
102 void emitStatement(AssertOp op) { emitVerifStatement(op,
"assert"); }
103 void emitStatement(AssumeOp op) { emitVerifStatement(op,
"assume"); }
104 void emitStatement(CoverOp op) { emitVerifStatement(op,
"cover"); }
107 void emitExpression(Value value);
108 void emitExpression(ConstantOp op);
109 void emitExpression(SpecialConstantOp op);
110 void emitExpression(SubfieldOp op);
111 void emitExpression(SubindexOp op);
112 void emitExpression(SubaccessOp op);
113 void emitExpression(OpenSubfieldOp op);
114 void emitExpression(OpenSubindexOp op);
115 void emitExpression(RefResolveOp op);
116 void emitExpression(RefSendOp op);
117 void emitExpression(RefSubOp op);
118 void emitExpression(RWProbeOp op);
119 void emitExpression(RefCastOp op);
120 void emitExpression(UninferredResetCastOp op);
121 void emitExpression(ConstCastOp op);
122 void emitExpression(StringConstantOp op);
123 void emitExpression(FIntegerConstantOp op);
124 void emitExpression(BoolConstantOp op);
125 void emitExpression(DoubleConstantOp op);
126 void emitExpression(ListCreateOp op);
127 void emitExpression(UnresolvedPathOp op);
128 void emitExpression(GenericIntrinsicOp op);
130 void emitPrimExpr(StringRef mnemonic, Operation *op,
131 ArrayRef<uint32_t> attrs = {});
133 void emitExpression(BitsPrimOp op) {
134 emitPrimExpr(
"bits", op, {op.getHi(), op.getLo()});
136 void emitExpression(HeadPrimOp op) {
137 emitPrimExpr(
"head", op, op.getAmount());
139 void emitExpression(TailPrimOp op) {
140 emitPrimExpr(
"tail", op, op.getAmount());
142 void emitExpression(PadPrimOp op) { emitPrimExpr(
"pad", op, op.getAmount()); }
143 void emitExpression(ShlPrimOp op) { emitPrimExpr(
"shl", op, op.getAmount()); }
144 void emitExpression(ShrPrimOp op) { emitPrimExpr(
"shr", op, op.getAmount()); }
147 #define HANDLE(OPTYPE, MNEMONIC) \
148 void emitExpression(OPTYPE op) { emitPrimExpr(MNEMONIC, op); }
164 HANDLE(DShlPrimOp,
"dshl");
165 HANDLE(DShlwPrimOp,
"dshlw");
166 HANDLE(DShrPrimOp,
"dshr");
168 HANDLE(AsSIntPrimOp,
"asSInt");
169 HANDLE(AsUIntPrimOp,
"asUInt");
170 HANDLE(AsAsyncResetPrimOp,
"asAsyncReset");
171 HANDLE(AsClockPrimOp,
"asClock");
175 HANDLE(AndRPrimOp,
"andr");
177 HANDLE(XorRPrimOp,
"xorr");
181 void emitAttribute(MemDirAttr attr);
182 void emitAttribute(RUWAttr attr);
185 void emitType(Type type,
bool includeConst =
true);
186 void emitTypeWithColon(Type type) {
187 ps << PP::space <<
":" << PP::nbsp;
192 void emitLocation(Location loc);
193 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
194 template <
typename... Args>
195 void emitLocationAndNewLine(Args... args) {
198 ps << PP::neverbreak;
199 emitLocation(args...);
203 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
204 llvm::function_ref<
void()> emitRHS,
206 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
208 ps.scopedBox(PP::ibox2, [&]() {
210 ps << *wordBeforeLHS << PP::space;
214 ps << PP::space << syntax << PP::nbsp;
216 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
221 void emitSubExprIBox2(Value v) {
222 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
227 template <
typename Container,
typename EachFn>
228 void interleaveComma(
const Container &c, EachFn eachFn) {
229 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
234 void interleaveComma(ValueRange ops) {
235 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
238 void emitStatementFunctionOp(
PPExtString name, Operation *op) {
241 ps.scopedBox(PP::ibox0, [&]() {
242 interleaveComma(op->getOperands());
245 emitLocationAndNewLine(op);
248 template <
typename EachFn,
typename Range>
249 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
252 ps.scopedBox(PP::ibox0, [&]() {
253 interleaveComma(r, eachFn);
258 void emitLiteralExpression(Type type, ValueRange values) {
259 return emitLiteralExpression(type, values,
260 [&](Value v) { emitSubExprIBox2(v); });
264 void emitSymbol(SymbolRefAttr symbol) {
265 ps.ibox(2, IndentStyle::Block);
266 ps << symbol.getRootReference();
267 for (
auto nested : symbol.getNestedReferences()) {
270 ps << nested.getAttr();
277 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
278 encounteredError =
true;
279 return op->emitError(message);
283 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
284 encounteredError =
true;
285 return op->emitOpError(message);
290 std::optional<StringRef> lookupEmittedName(Value value) {
291 auto it = valueNames.find(value);
292 if (it != valueNames.end())
299 void emitPendingNewlineIfNeeded() {
300 if (pendingNewline) {
301 pendingNewline =
false;
305 void setPendingNewline() {
307 pendingNewline =
true;
310 void startStatement() { emitPendingNewlineIfNeeded(); }
328 bool pendingNewline =
false;
331 bool encounteredError =
false;
336 DenseMap<Value, StringRef> valueNames;
337 StringSet<> valueNamesStorage;
341 StringAttr legalize(StringAttr attr) {
342 StringRef str = attr.getValue();
343 if (str.empty() || !
isdigit(str.front()))
348 void addValueName(Value value, StringAttr attr) {
349 valueNames.insert({value, attr.getValue()});
351 void addValueName(Value value, StringRef str) {
352 auto it = valueNamesStorage.insert(str);
353 valueNames.insert({value, it.first->getKey()});
355 void addForceable(Forceable op, StringAttr attr) {
356 addValueName(op.getData(), attr);
357 if (op.isForceable()) {
358 SmallString<32> rwName;
359 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
360 addValueName(op.getDataRef(), rwName);
369 SymbolTable symbolTable;
370 hw::InnerSymbolTableCollection istc;
371 hw::InnerRefNamespace irn{symbolTable, istc};
372 SymInfos(Operation *op) : symbolTable(op), istc(op){};
374 std::optional<std::reference_wrapper<SymInfos>> symInfos;
381 LogicalResult Emitter::finalize() {
return failure(encounteredError); }
384 void Emitter::emitCircuit(CircuitOp op) {
385 circuitNamespace.add(op);
386 SymInfos circuitSymInfos(op);
387 symInfos = circuitSymInfos;
389 ps <<
"FIRRTL version ";
396 ps <<
"circuit " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
399 for (
auto &bodyOp : *op.getBodyBlock()) {
400 if (encounteredError)
402 TypeSwitch<Operation *>(&bodyOp)
403 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](auto op) {
407 .Case<LayerOp>([&](
auto op) { emitDeclaration(op); })
408 .Case<OptionOp>([&](
auto op) { emitDeclaration(op); })
409 .Default([&](
auto op) {
410 emitOpError(op,
"not supported for emission inside circuit");
414 circuitNamespace.clear();
415 symInfos = std::nullopt;
418 void Emitter::emitEnabledLayers(ArrayRef<Attribute> layers) {
419 for (
auto layer : layers) {
421 ps.
cbox(2, IndentStyle::Block);
422 ps <<
"enablelayer" << PP::space;
423 emitSymbol(cast<SymbolRefAttr>(layer));
428 void Emitter::emitParamAssign(ParamDeclAttr param, Operation *op,
429 std::optional<PPExtString> wordBeforeLHS) {
431 ps << *wordBeforeLHS << PP::nbsp;
433 ps <<
PPExtString(param.getName().strref()) << PP::nbsp <<
"=" << PP::nbsp;
434 TypeSwitch<Attribute>(param.getValue())
435 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
436 .Case<FloatAttr>([&](
auto attr) {
438 attr.getValue().toString(str);
443 .Default([&](
auto attr) {
444 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
445 ps <<
"<unsupported-attr ";
451 void Emitter::emitGenericIntrinsic(GenericIntrinsicOp op) {
455 ps << op.getIntrinsic();
457 auto params = op.getParameters();
458 if (!params.empty()) {
460 ps.scopedBox(PP::ibox0, [&]() {
462 params.getAsRange<ParamDeclAttr>(),
463 [&](ParamDeclAttr param) { emitParamAssign(param, op); });
468 if (op.getNumResults() != 0)
469 emitTypeWithColon(op.getResult().getType());
471 if (op.getNumOperands() != 0) {
472 ps <<
"," << PP::space;
473 ps.
scopedBox(PP::ibox0, [&]() { interleaveComma(op->getOperands()); });
480 void Emitter::emitModule(FModuleOp op) {
482 ps.
cbox(4, IndentStyle::Block);
484 ps <<
"public" << PP::nbsp;
485 ps <<
"module " <<
PPExtString(legalize(op.getNameAttr()));
486 emitEnabledLayers(op.getLayers());
487 ps << PP::nbsp <<
":" << PP::end;
494 auto ports = op.getPorts();
495 emitModulePorts(ports, op.getArguments());
496 if (!ports.empty() && !op.getBodyBlock()->empty())
500 emitStatementsInBlock(*op.getBodyBlock());
503 valueNamesStorage.clear();
507 void Emitter::emitModule(FExtModuleOp op) {
509 ps.
cbox(4, IndentStyle::Block);
510 ps <<
"extmodule " <<
PPExtString(legalize(op.getNameAttr()));
511 emitEnabledLayers(op.getLayers());
512 ps << PP::nbsp <<
":" << PP::end;
519 auto ports = op.getPorts();
520 emitModulePorts(ports);
523 if (op.getDefname() && !op.getDefname()->empty()) {
525 ps <<
"defname = " <<
PPExtString(*op.getDefname());
530 emitModuleParameters(op, op.getParameters());
535 void Emitter::emitModule(FIntModuleOp op) {
537 ps.
cbox(4, IndentStyle::Block);
538 ps <<
"intmodule " <<
PPExtString(legalize(op.getNameAttr()));
539 emitEnabledLayers(op.getLayers());
540 ps << PP::nbsp <<
":" << PP::end;
547 auto ports = op.getPorts();
548 emitModulePorts(ports);
551 ps <<
"intrinsic = " <<
PPExtString(op.getIntrinsic());
555 emitModuleParameters(op, op.getParameters());
562 void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
563 Block::BlockArgListType arguments) {
564 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
566 const auto &port = ports[i];
567 ps << (port.direction ==
Direction::In ?
"input " :
"output ");
568 auto legalName = legalize(port.name);
569 if (!arguments.empty())
570 addValueName(arguments[i], legalName);
573 emitLocation(ports[i].loc);
578 void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
579 for (
auto param : parameters.getAsRange<ParamDeclAttr>()) {
581 emitParamAssign(param, op,
PPExtString(
"parameter"));
587 void Emitter::emitDeclaration(LayerOp op) {
589 ps <<
"layer " <<
PPExtString(op.getSymName()) <<
", "
590 <<
PPExtString(stringifyLayerConvention(op.getConvention())) <<
" : ";
591 emitLocationAndNewLine(op);
593 for (
auto &bodyOp : op.getBody().getOps()) {
594 TypeSwitch<Operation *>(&bodyOp)
595 .Case<LayerOp>([&](auto op) { emitDeclaration(op); })
596 .Default([&](
auto op) {
598 "not supported for emission inside layer definition");
605 void Emitter::emitDeclaration(OptionOp op) {
607 ps <<
"option " <<
PPExtString(legalize(op.getSymNameAttr())) <<
" :";
610 for (
auto caseOp : op.getBody().getOps<OptionCaseOp>()) {
612 ps << PPExtString(legalize(caseOp.getSymNameAttr()));
613 emitLocation(caseOp);
616 ps << PP::newline << PP::newline;
627 return (
isExpression(op) && !isa<InvalidValueOp>(op)) ||
628 (isa<GenericIntrinsicOp>(op) && op->hasOneUse() &&
632 void Emitter::emitStatementsInBlock(Block &block) {
633 for (
auto &bodyOp : block) {
634 if (encounteredError)
638 TypeSwitch<Operation *>(&bodyOp)
639 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
640 PrintFOp, AssertOp, AssumeOp, CoverOp, ConnectOp, StrictConnectOp,
641 PropAssignOp, InstanceOp, InstanceChoiceOp, AttachOp, MemOp,
642 InvalidValueOp, SeqMemOp, CombMemOp, MemoryPortOp,
643 MemoryDebugPortOp, MemoryPortAccessOp, RefDefineOp, RefForceOp,
644 RefForceInitialOp, RefReleaseOp, RefReleaseInitialOp,
645 LayerBlockOp, GenericIntrinsicOp>(
646 [&](
auto op) { emitStatement(op); })
647 .Default([&](
auto op) {
649 ps <<
"// operation " <<
PPExtString(op->getName().getStringRef());
651 emitOpError(op,
"not supported as statement");
656 void Emitter::emitStatement(WhenOp op) {
659 emitExpression(op.getCondition());
661 emitLocationAndNewLine(op);
662 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
664 if (!op.hasElseRegion())
671 auto &elseBlock = op.getElseBlock();
672 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
673 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
674 emitStatement(whenOp);
681 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
684 void Emitter::emitStatement(WireOp op) {
685 auto legalName = legalize(op.getNameAttr());
686 addForceable(op, legalName);
690 emitTypeWithColon(op.getResult().getType());
692 emitLocationAndNewLine(op);
695 void Emitter::emitStatement(RegOp op) {
696 auto legalName = legalize(op.getNameAttr());
697 addForceable(op, legalName);
701 emitTypeWithColon(op.getResult().getType());
702 ps <<
"," << PP::space;
703 emitExpression(op.getClockVal());
705 emitLocationAndNewLine(op);
708 void Emitter::emitStatement(RegResetOp op) {
709 auto legalName = legalize(op.getNameAttr());
710 addForceable(op, legalName);
714 ps <<
"regreset " << legalName;
715 emitTypeWithColon(op.getResult().getType());
716 ps <<
"," << PP::space;
717 emitExpression(op.getClockVal());
718 ps <<
"," << PP::space;
719 emitExpression(op.getResetSignal());
720 ps <<
"," << PP::space;
721 emitExpression(op.getResetValue());
725 ps <<
"reg " << legalName;
726 emitTypeWithColon(op.getResult().getType());
727 ps <<
"," << PP::space;
728 emitExpression(op.getClockVal());
729 ps << PP::space <<
"with :";
731 ps << PP::neverbreak;
734 ps <<
"reset => (" << PP::ibox0;
735 emitExpression(op.getResetSignal());
736 ps <<
"," << PP::space;
737 emitExpression(op.getResetValue());
738 ps <<
")" << PP::end;
741 emitLocationAndNewLine(op);
744 void Emitter::emitStatement(NodeOp op) {
745 auto legalName = legalize(op.getNameAttr());
746 addForceable(op, legalName);
748 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(legalName); },
749 [&]() { emitExpression(op.getInput()); });
750 emitLocationAndNewLine(op);
753 void Emitter::emitStatement(StopOp op) {
756 ps <<
"stop(" << PP::ibox0;
757 emitExpression(op.getClock());
758 ps <<
"," << PP::space;
759 emitExpression(op.getCond());
760 ps <<
"," << PP::space;
762 ps <<
")" << PP::end;
763 if (!op.getName().empty()) {
764 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
767 emitLocationAndNewLine(op);
770 void Emitter::emitStatement(SkipOp op) {
773 emitLocationAndNewLine(op);
776 void Emitter::emitStatement(PrintFOp op) {
779 ps <<
"printf(" << PP::ibox0;
780 emitExpression(op.getClock());
781 ps <<
"," << PP::space;
782 emitExpression(op.getCond());
783 ps <<
"," << PP::space;
785 for (
auto operand : op.getSubstitutions()) {
786 ps <<
"," << PP::space;
787 emitExpression(operand);
789 ps <<
")" << PP::end;
790 if (!op.getName().empty()) {
791 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
794 emitLocationAndNewLine(op);
798 void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
801 ps << mnemonic <<
"(" << PP::ibox0;
802 emitExpression(op.getClock());
803 ps <<
"," << PP::space;
804 emitExpression(op.getPredicate());
805 ps <<
"," << PP::space;
806 emitExpression(op.getEnable());
807 ps <<
"," << PP::space;
809 ps <<
")" << PP::end;
810 if (!op.getName().empty()) {
811 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
814 emitLocationAndNewLine(op);
817 void Emitter::emitStatement(ConnectOp op) {
821 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
822 ps <<
"invalidate" << PP::space;
823 emitExpression(op.getDest());
825 ps <<
"connect" << PP::space;
826 emitExpression(op.getDest());
827 ps <<
"," << PP::space;
828 emitExpression(op.getSrc());
832 auto emitLHS = [&]() { emitExpression(op.getDest()); };
833 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
835 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
838 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
841 emitLocationAndNewLine(op);
844 void Emitter::emitStatement(StrictConnectOp op) {
848 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
849 ps <<
"invalidate" << PP::space;
850 emitExpression(op.getDest());
852 ps <<
"connect" << PP::space;
853 emitExpression(op.getDest());
854 ps <<
"," << PP::space;
855 emitExpression(op.getSrc());
859 auto emitLHS = [&]() { emitExpression(op.getDest()); };
860 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
862 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
865 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
868 emitLocationAndNewLine(op);
871 void Emitter::emitStatement(PropAssignOp op) {
874 ps <<
"propassign" << PP::space;
875 interleaveComma(op.getOperands());
877 emitLocationAndNewLine(op);
880 void Emitter::emitStatement(InstanceOp op) {
882 auto legalName = legalize(op.getNameAttr());
884 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
885 emitLocationAndNewLine(op);
889 SmallString<16> portName(legalName);
890 portName.push_back(
'.');
891 unsigned baseLen = portName.size();
892 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
893 portName.append(legalize(op.getPortName(i)));
894 addValueName(op.getResult(i), portName);
895 portName.resize(baseLen);
899 void Emitter::emitStatement(InstanceChoiceOp op) {
901 auto legalName = legalize(op.getNameAttr());
902 ps <<
"instchoice " <<
PPExtString(legalName) <<
" of "
903 <<
PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
904 <<
PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
907 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
909 ps << PPExtString(legalize(optSym.getLeafReference()));
911 ps << PPExtString(legalize(targetSym.getAttr()));
916 SmallString<16> portName(legalName);
917 portName.push_back(
'.');
918 unsigned baseLen = portName.size();
919 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
920 portName.append(legalize(op.getPortName(i)));
921 addValueName(op.getResult(i), portName);
922 portName.resize(baseLen);
926 void Emitter::emitStatement(AttachOp op) {
927 emitStatementFunctionOp(
PPExtString(
"attach"), op);
930 void Emitter::emitStatement(MemOp op) {
931 auto legalName = legalize(op.getNameAttr());
932 SmallString<16> portName(legalName);
933 portName.push_back(
'.');
934 auto portNameBaseLen = portName.size();
935 for (
auto result : llvm::zip(op.getResults(), op.getPortNames())) {
936 portName.resize(portNameBaseLen);
937 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
938 addValueName(std::get<0>(result), portName);
943 emitLocationAndNewLine(op);
946 ps <<
"data-type => ";
947 emitType(op.getDataType());
952 ps <<
"read-latency => ";
955 ps <<
"write-latency => ";
959 SmallString<16> reader, writer, readwriter;
960 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
961 auto add = [&](SmallString<16> &to, StringAttr name) {
964 to.append(name.getValue());
966 switch (port.second) {
967 case MemOp::PortKind::Read:
968 add(reader, legalize(port.first));
970 case MemOp::PortKind::Write:
971 add(writer, legalize(port.first));
973 case MemOp::PortKind::ReadWrite:
974 add(readwriter, legalize(port.first));
976 case MemOp::PortKind::Debug:
977 emitOpError(op,
"has unsupported 'debug' port");
982 ps <<
"reader => " << reader << PP::newline;
984 ps <<
"writer => " << writer << PP::newline;
985 if (!readwriter.empty())
986 ps <<
"readwriter => " << readwriter << PP::newline;
988 ps <<
"read-under-write => ";
989 emitAttribute(op.getRuw());
994 void Emitter::emitStatement(SeqMemOp op) {
997 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
998 emitTypeWithColon(op.getType());
1000 emitAttribute(op.getRuw());
1002 emitLocationAndNewLine(op);
1005 void Emitter::emitStatement(CombMemOp op) {
1008 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
1009 emitTypeWithColon(op.getType());
1011 emitLocationAndNewLine(op);
1014 void Emitter::emitStatement(MemoryPortOp op) {
1016 addValueName(op.getData(), legalize(op.getNameAttr()));
1019 void Emitter::emitStatement(MemoryDebugPortOp op) {
1021 addValueName(op.getData(), legalize(op.getNameAttr()));
1024 void Emitter::emitStatement(MemoryPortAccessOp op) {
1028 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1029 emitAttribute(port.getDirection());
1031 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
1034 auto *mem = port.getMemory().getDefiningOp();
1035 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1036 ps << legalize(seqMem.getNameAttr());
1038 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1042 emitExpression(op.getIndex());
1046 emitExpression(op.getClock());
1048 emitLocationAndNewLine(op);
1051 void Emitter::emitStatement(RefDefineOp op) {
1053 emitAssignLike([&]() { emitExpression(op.getDest()); },
1054 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1056 emitLocationAndNewLine(op);
1059 void Emitter::emitStatement(RefForceOp op) {
1060 emitStatementFunctionOp(
PPExtString(
"force"), op);
1063 void Emitter::emitStatement(RefForceInitialOp op) {
1065 auto constantPredicate =
1066 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1067 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1070 emitExpression(op.getPredicate());
1071 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1073 ps <<
"force_initial(";
1075 interleaveComma({op.getDest(), op.getSrc()});
1080 emitLocationAndNewLine(op);
1083 void Emitter::emitStatement(RefReleaseOp op) {
1084 emitStatementFunctionOp(
PPExtString(
"release"), op);
1087 void Emitter::emitStatement(RefReleaseInitialOp op) {
1089 auto constantPredicate =
1090 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1091 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1094 emitExpression(op.getPredicate());
1095 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1097 ps <<
"release_initial(";
1098 emitExpression(op.getDest());
1102 emitLocationAndNewLine(op);
1105 void Emitter::emitStatement(LayerBlockOp op) {
1107 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1108 emitLocationAndNewLine(op);
1109 auto *body = op.getBody();
1110 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1113 void Emitter::emitStatement(InvalidValueOp op) {
1116 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1117 return use.getOperandNumber() == 1 &&
1118 isa<ConnectOp, StrictConnectOp>(use.getOwner());
1124 auto name = circuitNamespace.newName(
"_invalid");
1125 addValueName(op, name);
1127 emitType(op.getType());
1128 emitLocationAndNewLine(op);
1134 emitLocationAndNewLine(op);
1137 void Emitter::emitStatement(GenericIntrinsicOp op) {
1140 emitGenericIntrinsic(op);
1143 auto name = circuitNamespace.newName(
"_gen_int");
1144 addValueName(op.getResult(), name);
1145 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(name); },
1146 [&]() { emitGenericIntrinsic(op); });
1148 emitLocationAndNewLine(op);
1151 void Emitter::emitExpression(Value value) {
1154 if (
auto name = lookupEmittedName(value)) {
1160 auto op = value.getDefiningOp();
1161 assert(op &&
"value must either be a block arg or the result of an op");
1162 TypeSwitch<Operation *>(op)
1165 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1166 OpenSubfieldOp, OpenSubindexOp,
1168 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1169 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1170 EQPrimOp, NEQPrimOp, CatPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1172 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsClockPrimOp,
1173 CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp, XorRPrimOp,
1175 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1176 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1177 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1178 UnresolvedPathOp, GenericIntrinsicOp,
1180 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp>(
1182 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1184 .Default([&](
auto op) {
1185 emitOpError(op,
"not supported as expression");
1186 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1191 void Emitter::emitExpression(ConstantOp op) {
1193 emitType(op.getType(),
false);
1200 void Emitter::emitExpression(SpecialConstantOp op) {
1201 auto emitInner = [&]() {
1208 .
Case<ClockType>([&](
auto type) {
1213 .Case<ResetType>([&](
auto type) { emitInner(); })
1214 .Case<AsyncResetType>([&](
auto type) {
1215 ps <<
"asAsyncReset(";
1222 void Emitter::emitExpression(SubfieldOp op) {
1223 BundleType type = op.getInput().getType();
1224 emitExpression(op.getInput());
1225 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1229 void Emitter::emitExpression(SubindexOp op) {
1230 emitExpression(op.getInput());
1237 void Emitter::emitExpression(SubaccessOp op) {
1238 emitExpression(op.getInput());
1240 emitExpression(op.getIndex());
1244 void Emitter::emitExpression(OpenSubfieldOp op) {
1245 auto type = op.getInput().getType();
1246 emitExpression(op.getInput());
1247 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1250 void Emitter::emitExpression(OpenSubindexOp op) {
1251 emitExpression(op.getInput());
1257 void Emitter::emitExpression(RefSendOp op) {
1259 emitExpression(op.getBase());
1263 void Emitter::emitExpression(RefResolveOp op) {
1265 emitExpression(op.getRef());
1269 void Emitter::emitExpression(RefSubOp op) {
1270 emitExpression(op.getInput());
1272 .
Case<FVectorType>([&](
auto type) {
1278 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1281 void Emitter::emitExpression(RWProbeOp op) {
1285 auto target = symInfos->get().irn.lookup(op.getTarget());
1287 if (target.isPort()) {
1288 auto mod = cast<FModuleOp>(target.getOp());
1289 auto port = target.getPort();
1290 base = mod.getArgument(port);
1292 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1295 emitExpression(base);
1298 auto fieldID = target.getField();
1299 auto type = base.getType();
1302 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1303 auto index = vecTy.getIndexForFieldID(fieldID);
1307 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1309 fieldID = subfieldID;
1311 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1312 auto index = bundleTy.getIndexForFieldID(fieldID);
1313 ps <<
"." << bundleTy.getElementName(index);
1314 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1316 fieldID = subfieldID;
1322 void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1324 void Emitter::emitExpression(UninferredResetCastOp op) {
1325 emitExpression(op.getInput());
1328 void Emitter::emitExpression(FIntegerConstantOp op) {
1334 void Emitter::emitExpression(BoolConstantOp op) {
1335 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1338 void Emitter::emitExpression(DoubleConstantOp op) {
1344 SmallString<16> str;
1345 op.getValueAttr().getValue().toString(str);
1350 void Emitter::emitExpression(StringConstantOp op) {
1356 void Emitter::emitExpression(ListCreateOp op) {
1357 return emitLiteralExpression(op.getType(), op.getElements());
1360 void Emitter::emitExpression(UnresolvedPathOp op) {
1366 void Emitter::emitExpression(GenericIntrinsicOp op) {
1367 emitGenericIntrinsic(op);
1370 void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1372 void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1373 ArrayRef<uint32_t> attrs) {
1374 ps << mnemonic <<
"(" << PP::ibox0;
1375 interleaveComma(op->getOperands());
1376 if (!op->getOperands().empty() && !attrs.empty())
1377 ps <<
"," << PP::space;
1378 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1379 ps <<
")" << PP::end;
1382 void Emitter::emitAttribute(MemDirAttr attr) {
1384 case MemDirAttr::Infer:
1387 case MemDirAttr::Read:
1390 case MemDirAttr::Write:
1393 case MemDirAttr::ReadWrite:
1399 void Emitter::emitAttribute(RUWAttr attr) {
1401 case RUWAttr::Undefined:
1414 void Emitter::emitType(Type type,
bool includeConst) {
1415 if (includeConst &&
isConst(type))
1417 auto emitWidth = [&](std::optional<int32_t>
width) {
1426 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1427 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1428 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1429 .Case<UIntType>([&](
auto type) {
1431 emitWidth(type.getWidth());
1433 .Case<SIntType>([&](
auto type) {
1435 emitWidth(type.getWidth());
1437 .Case<AnalogType>([&](
auto type) {
1439 emitWidth(type.getWidth());
1441 .Case<OpenBundleType, BundleType>([&](
auto type) {
1443 if (!type.getElements().empty())
1445 bool anyEmitted =
false;
1447 for (
auto &element : type.getElements()) {
1449 ps <<
"," << PP::space;
1450 ps.scopedBox(PP::ibox2, [&]() {
1453 ps << legalize(element.name);
1454 emitTypeWithColon(element.type);
1463 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1464 emitType(type.getElementType());
1469 .Case<RefType>([&](RefType type) {
1470 if (type.getForceable())
1473 ps.
cbox(2, IndentStyle::Block);
1475 emitType(type.getType());
1476 if (
auto layer = type.getLayer()) {
1479 emitSymbol(type.getLayer());
1484 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1485 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1486 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1487 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1488 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1489 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1490 .Case<ListType>([&](ListType type) {
1492 emitType(type.getElementType());
1495 .Default([&](
auto type) {
1496 llvm_unreachable(
"all types should be implemented");
1502 void Emitter::emitLocation(Location loc) {
1504 ps << PP::neverbreak;
1505 if (
auto fileLoc = loc->dyn_cast_or_null<FileLineColLoc>()) {
1506 ps <<
" @[" << fileLoc.getFilename().getValue();
1507 if (
auto line = fileLoc.getLine()) {
1510 if (
auto col = fileLoc.getColumn()) {
1527 std::optional<size_t> targetLineLength,
1529 Emitter emitter(os, version,
1530 targetLineLength.value_or(defaultTargetLineLength));
1531 for (
auto &op : *module.getBody()) {
1532 if (
auto circuitOp = dyn_cast<CircuitOp>(op))
1533 emitter.emitCircuit(circuitOp);
1535 return emitter.finalize();
1540 "target-line-length",
1541 llvm::cl::desc(
"Target line length for emitted .fir"),
1542 llvm::cl::value_desc(
"number of chars"),
1543 llvm::cl::init(defaultTargetLineLength));
1544 static mlir::TranslateFromMLIRRegistration toFIR(
1545 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
1546 [](ModuleOp module, llvm::raw_ostream &os) {
1549 [](mlir::DialectRegistry ®istry) {
1550 registry.insert<chirrtl::CHIRRTLDialect>();
1551 registry.insert<firrtl::FIRRTLDialect>();
assert(baseType &&"element must be base type")
#define HANDLE(OPTYPE, MNEMONIC)
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)
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.
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 & writeQuotedEscaped(StringRef str, bool useHexEscapes=false, StringRef left="\"", StringRef right="\"")
TokenStream & addAsString(T &&t)
General-purpose "format this" helper, for types not supported by operator<< yet.
PrettyPrinter::Listener that saves strings while live.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::LogicalResult exportFIRFile(mlir::ModuleOp module, llvm::raw_ostream &os, std::optional< size_t > targetLineLength, FIRVersion version)
constexpr FIRVersion exportFIRVersion(4, 0, 0)
void registerToFIRFileTranslation()
bool isConst(Type type)
Returns true if this is a 'const' type whose value is guaranteed to be unchanging at circuit executio...
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
The namespace of a CircuitOp, generally inhabited by modules.
The FIRRTL specification version.
String wrapper to indicate string has external storage.