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(GroupDeclOp op);
64 void emitStatementsInBlock(
Block &block);
65 void emitStatement(WhenOp op);
66 void emitStatement(WireOp op);
67 void emitStatement(RegOp op);
68 void emitStatement(RegResetOp op);
69 void emitStatement(NodeOp op);
70 void emitStatement(StopOp op);
71 void emitStatement(SkipOp op);
72 void emitStatement(PrintFOp op);
73 void emitStatement(ConnectOp op);
74 void emitStatement(StrictConnectOp op);
75 void emitStatement(PropAssignOp op);
76 void emitStatement(InstanceOp op);
77 void emitStatement(AttachOp op);
78 void emitStatement(MemOp op);
79 void emitStatement(InvalidValueOp op);
80 void emitStatement(CombMemOp op);
81 void emitStatement(SeqMemOp op);
82 void emitStatement(MemoryPortOp op);
83 void emitStatement(MemoryDebugPortOp op);
84 void emitStatement(MemoryPortAccessOp op);
85 void emitStatement(RefDefineOp op);
86 void emitStatement(RefForceOp op);
87 void emitStatement(RefForceInitialOp op);
88 void emitStatement(RefReleaseOp op);
89 void emitStatement(RefReleaseInitialOp op);
90 void emitStatement(GroupOp op);
93 void emitVerifStatement(T op, StringRef mnemonic);
94 void emitStatement(AssertOp op) { emitVerifStatement(op,
"assert"); }
95 void emitStatement(AssumeOp op) { emitVerifStatement(op,
"assume"); }
96 void emitStatement(CoverOp op) { emitVerifStatement(op,
"cover"); }
99 void emitExpression(Value value);
100 void emitExpression(ConstantOp op);
101 void emitExpression(SpecialConstantOp op);
102 void emitExpression(SubfieldOp op);
103 void emitExpression(SubindexOp op);
104 void emitExpression(SubaccessOp op);
105 void emitExpression(OpenSubfieldOp op);
106 void emitExpression(OpenSubindexOp op);
107 void emitExpression(RefResolveOp op);
108 void emitExpression(RefSendOp op);
109 void emitExpression(RefSubOp op);
110 void emitExpression(RWProbeOp op);
111 void emitExpression(RefCastOp op);
112 void emitExpression(UninferredResetCastOp op);
113 void emitExpression(ConstCastOp op);
114 void emitExpression(StringConstantOp op);
115 void emitExpression(FIntegerConstantOp op);
116 void emitExpression(BoolConstantOp op);
117 void emitExpression(DoubleConstantOp op);
118 void emitExpression(ListCreateOp op);
119 void emitExpression(UnresolvedPathOp op);
121 void emitPrimExpr(StringRef mnemonic, Operation *op,
122 ArrayRef<uint32_t> attrs = {});
124 void emitExpression(BitsPrimOp op) {
125 emitPrimExpr(
"bits", op, {op.getHi(), op.getLo()});
127 void emitExpression(HeadPrimOp op) {
128 emitPrimExpr(
"head", op, op.getAmount());
130 void emitExpression(TailPrimOp op) {
131 emitPrimExpr(
"tail", op, op.getAmount());
133 void emitExpression(PadPrimOp op) { emitPrimExpr(
"pad", op, op.getAmount()); }
134 void emitExpression(ShlPrimOp op) { emitPrimExpr(
"shl", op, op.getAmount()); }
135 void emitExpression(ShrPrimOp op) { emitPrimExpr(
"shr", op, op.getAmount()); }
138 #define HANDLE(OPTYPE, MNEMONIC) \
139 void emitExpression(OPTYPE op) { emitPrimExpr(MNEMONIC, op); }
155 HANDLE(DShlPrimOp,
"dshl");
156 HANDLE(DShlwPrimOp,
"dshlw");
157 HANDLE(DShrPrimOp,
"dshr");
159 HANDLE(AsSIntPrimOp,
"asSInt");
160 HANDLE(AsUIntPrimOp,
"asUInt");
161 HANDLE(AsAsyncResetPrimOp,
"asAsyncReset");
162 HANDLE(AsClockPrimOp,
"asClock");
166 HANDLE(AndRPrimOp,
"andr");
168 HANDLE(XorRPrimOp,
"xorr");
172 void emitAttribute(MemDirAttr attr);
173 void emitAttribute(RUWAttr attr);
176 void emitType(Type type,
bool includeConst =
true);
177 void emitTypeWithColon(Type type) {
178 ps << PP::space <<
":" << PP::nbsp;
183 void emitLocation(Location loc);
184 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
185 template <
typename... Args>
186 void emitLocationAndNewLine(Args... args) {
189 ps << PP::neverbreak;
190 emitLocation(args...);
194 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
195 llvm::function_ref<
void()> emitRHS,
197 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
199 ps.scopedBox(PP::ibox2, [&]() {
201 ps << *wordBeforeLHS << PP::space;
205 ps << PP::space << syntax << PP::nbsp;
207 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
212 void emitSubExprIBox2(Value v) {
213 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
218 template <
typename Container,
typename EachFn>
219 void interleaveComma(
const Container &c, EachFn eachFn) {
220 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
225 void interleaveComma(ValueRange ops) {
226 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
229 void emitStatementFunctionOp(
PPExtString name, Operation *op) {
232 ps.scopedBox(PP::ibox0, [&]() {
233 interleaveComma(op->getOperands());
236 emitLocationAndNewLine(op);
239 template <
typename EachFn,
typename Range>
240 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
243 ps.scopedBox(PP::ibox0, [&]() {
244 interleaveComma(r, eachFn);
249 void emitLiteralExpression(Type type, ValueRange values) {
250 return emitLiteralExpression(type, values,
251 [&](Value v) { emitSubExprIBox2(v); });
256 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
257 encounteredError =
true;
258 return op->emitError(message);
262 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
263 encounteredError =
true;
264 return op->emitOpError(message);
269 std::optional<StringRef> lookupEmittedName(Value value) {
270 auto it = valueNames.find(value);
271 if (it != valueNames.end())
278 void emitPendingNewlineIfNeeded() {
279 if (pendingNewline) {
280 pendingNewline =
false;
284 void setPendingNewline() {
286 pendingNewline =
true;
289 void startStatement() { emitPendingNewlineIfNeeded(); }
307 bool pendingNewline =
false;
310 bool encounteredError =
false;
315 DenseMap<Value, StringRef> valueNames;
316 StringSet<> valueNamesStorage;
320 StringAttr legalize(StringAttr attr) {
321 StringRef str = attr.getValue();
322 if (str.empty() || !
isdigit(str.front()))
327 void addValueName(Value value, StringAttr attr) {
328 valueNames.insert({value, attr.getValue()});
330 void addValueName(Value value, StringRef str) {
331 auto it = valueNamesStorage.insert(str);
332 valueNames.insert({value, it.first->getKey()});
334 void addForceable(Forceable op, StringAttr attr) {
335 addValueName(op.getData(), attr);
336 if (op.isForceable()) {
337 SmallString<32> rwName;
338 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
339 addValueName(op.getDataRef(), rwName);
348 SymbolTable symbolTable;
349 hw::InnerSymbolTableCollection istc;
350 hw::InnerRefNamespace irn{symbolTable, istc};
351 SymInfos(Operation *op) : symbolTable(op), istc(op){};
353 std::optional<std::reference_wrapper<SymInfos>> symInfos;
360 LogicalResult Emitter::finalize() {
return failure(encounteredError); }
363 void Emitter::emitCircuit(CircuitOp op) {
364 circuitNamespace.add(op);
365 SymInfos circuitSymInfos(op);
366 symInfos = circuitSymInfos;
368 ps <<
"FIRRTL version ";
375 ps <<
"circuit " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
378 for (
auto &bodyOp : *op.getBodyBlock()) {
379 if (encounteredError)
381 TypeSwitch<Operation *>(&bodyOp)
382 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](auto op) {
386 .Case<GroupDeclOp>([&](
auto op) { emitDeclaration(op); })
387 .Default([&](
auto op) {
388 emitOpError(op,
"not supported for emission inside circuit");
392 circuitNamespace.clear();
393 symInfos = std::nullopt;
397 void Emitter::emitModule(FModuleOp op) {
399 ps <<
"module " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
405 auto ports = op.getPorts();
406 emitModulePorts(ports, op.getArguments());
407 if (!ports.empty() && !op.getBodyBlock()->empty())
411 emitStatementsInBlock(*op.getBodyBlock());
414 valueNamesStorage.clear();
418 void Emitter::emitModule(FExtModuleOp op) {
420 ps <<
"extmodule " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
426 auto ports = op.getPorts();
427 emitModulePorts(ports);
430 if (op.getDefname() && !op.getDefname()->empty()) {
432 ps <<
"defname = " <<
PPExtString(*op.getDefname());
437 emitModuleParameters(op, op.getParameters());
442 void Emitter::emitModule(FIntModuleOp op) {
444 ps <<
"intmodule " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
450 auto ports = op.getPorts();
451 emitModulePorts(ports);
457 if (op.getIntrinsic().has_value()) {
458 auto intrinsic = *op.getIntrinsic();
459 if (!intrinsic.empty()) {
461 ps <<
"intrinsic = " <<
PPExtString(*op.getIntrinsic());
467 emitModuleParameters(op, op.getParameters());
474 void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
475 Block::BlockArgListType arguments) {
476 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
478 const auto &port = ports[i];
479 ps << (port.direction ==
Direction::In ?
"input " :
"output ");
480 auto legalName = legalize(port.name);
481 if (!arguments.empty())
482 addValueName(arguments[i], legalName);
485 emitLocation(ports[i].loc);
490 void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
491 for (
auto param : llvm::map_range(parameters, [](Attribute attr) {
492 return cast<ParamDeclAttr>(attr);
496 ps <<
"parameter " <<
PPExtString(param.getName().getValue()) <<
" = ";
497 TypeSwitch<Attribute>(param.getValue())
498 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
499 .Case<FloatAttr>([&](
auto attr) {
501 attr.getValue().toString(str);
506 .Default([&](
auto attr) {
507 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
508 ps <<
"<unsupported-attr ";
517 void Emitter::emitDeclaration(GroupDeclOp op) {
519 ps <<
"declgroup " <<
PPExtString(op.getSymName()) <<
", "
520 <<
PPExtString(stringifyGroupConvention(op.getConvention())) <<
" : ";
521 emitLocationAndNewLine(op);
523 for (
auto &bodyOp : op.getBody().getOps()) {
524 TypeSwitch<Operation *>(&bodyOp)
525 .Case<GroupDeclOp>([&](auto op) { emitDeclaration(op); })
526 .Default([&](
auto op) {
528 "not supported for emission inside group declaration");
540 void Emitter::emitStatementsInBlock(Block &block) {
541 for (
auto &bodyOp : block) {
542 if (encounteredError)
546 TypeSwitch<Operation *>(&bodyOp)
547 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
548 PrintFOp, AssertOp, AssumeOp, CoverOp, ConnectOp, StrictConnectOp,
549 PropAssignOp, InstanceOp, AttachOp, MemOp, InvalidValueOp,
550 SeqMemOp, CombMemOp, MemoryPortOp, MemoryDebugPortOp,
551 MemoryPortAccessOp, RefDefineOp, RefForceOp, RefForceInitialOp,
552 RefReleaseOp, RefReleaseInitialOp, GroupOp>(
553 [&](
auto op) { emitStatement(op); })
554 .Default([&](
auto op) {
556 ps <<
"// operation " <<
PPExtString(op->getName().getStringRef());
558 emitOpError(op,
"not supported as statement");
563 void Emitter::emitStatement(WhenOp op) {
566 emitExpression(op.getCondition());
568 emitLocationAndNewLine(op);
569 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
571 if (!op.hasElseRegion())
578 auto &elseBlock = op.getElseBlock();
579 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
580 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
581 emitStatement(whenOp);
588 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
591 void Emitter::emitStatement(WireOp op) {
592 auto legalName = legalize(op.getNameAttr());
593 addForceable(op, legalName);
597 emitTypeWithColon(op.getResult().getType());
599 emitLocationAndNewLine(op);
602 void Emitter::emitStatement(RegOp op) {
603 auto legalName = legalize(op.getNameAttr());
604 addForceable(op, legalName);
608 emitTypeWithColon(op.getResult().getType());
609 ps <<
"," << PP::space;
610 emitExpression(op.getClockVal());
612 emitLocationAndNewLine(op);
615 void Emitter::emitStatement(RegResetOp op) {
616 auto legalName = legalize(op.getNameAttr());
617 addForceable(op, legalName);
621 ps <<
"regreset " << legalName;
622 emitTypeWithColon(op.getResult().getType());
623 ps <<
"," << PP::space;
624 emitExpression(op.getClockVal());
625 ps <<
"," << PP::space;
626 emitExpression(op.getResetSignal());
627 ps <<
"," << PP::space;
628 emitExpression(op.getResetValue());
632 ps <<
"reg " << legalName;
633 emitTypeWithColon(op.getResult().getType());
634 ps <<
"," << PP::space;
635 emitExpression(op.getClockVal());
636 ps << PP::space <<
"with :";
638 ps << PP::neverbreak;
641 ps <<
"reset => (" << PP::ibox0;
642 emitExpression(op.getResetSignal());
643 ps <<
"," << PP::space;
644 emitExpression(op.getResetValue());
645 ps <<
")" << PP::end;
648 emitLocationAndNewLine(op);
651 void Emitter::emitStatement(NodeOp op) {
652 auto legalName = legalize(op.getNameAttr());
653 addForceable(op, legalName);
655 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(legalName); },
656 [&]() { emitExpression(op.getInput()); });
657 emitLocationAndNewLine(op);
660 void Emitter::emitStatement(StopOp op) {
663 ps <<
"stop(" << PP::ibox0;
664 emitExpression(op.getClock());
665 ps <<
"," << PP::space;
666 emitExpression(op.getCond());
667 ps <<
"," << PP::space;
669 ps <<
")" << PP::end;
670 if (!op.getName().empty()) {
671 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
674 emitLocationAndNewLine(op);
677 void Emitter::emitStatement(SkipOp op) {
680 emitLocationAndNewLine(op);
683 void Emitter::emitStatement(PrintFOp op) {
686 ps <<
"printf(" << PP::ibox0;
687 emitExpression(op.getClock());
688 ps <<
"," << PP::space;
689 emitExpression(op.getCond());
690 ps <<
"," << PP::space;
692 for (
auto operand : op.getSubstitutions()) {
693 ps <<
"," << PP::space;
694 emitExpression(operand);
696 ps <<
")" << PP::end;
697 if (!op.getName().empty()) {
698 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
701 emitLocationAndNewLine(op);
705 void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
708 ps << mnemonic <<
"(" << PP::ibox0;
709 emitExpression(op.getClock());
710 ps <<
"," << PP::space;
711 emitExpression(op.getPredicate());
712 ps <<
"," << PP::space;
713 emitExpression(op.getEnable());
714 ps <<
"," << PP::space;
716 ps <<
")" << PP::end;
717 if (!op.getName().empty()) {
718 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
721 emitLocationAndNewLine(op);
724 void Emitter::emitStatement(ConnectOp op) {
728 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
729 ps <<
"invalidate" << PP::space;
730 emitExpression(op.getDest());
732 ps <<
"connect" << PP::space;
733 emitExpression(op.getDest());
734 ps <<
"," << PP::space;
735 emitExpression(op.getSrc());
739 auto emitLHS = [&]() { emitExpression(op.getDest()); };
740 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
742 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
745 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
748 emitLocationAndNewLine(op);
751 void Emitter::emitStatement(StrictConnectOp op) {
755 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
756 ps <<
"invalidate" << PP::space;
757 emitExpression(op.getDest());
759 ps <<
"connect" << PP::space;
760 emitExpression(op.getDest());
761 ps <<
"," << PP::space;
762 emitExpression(op.getSrc());
766 auto emitLHS = [&]() { emitExpression(op.getDest()); };
767 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
769 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
772 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
775 emitLocationAndNewLine(op);
778 void Emitter::emitStatement(PropAssignOp op) {
781 ps <<
"propassign" << PP::space;
782 interleaveComma(op.getOperands());
784 emitLocationAndNewLine(op);
787 void Emitter::emitStatement(InstanceOp op) {
789 auto legalName = legalize(op.getNameAttr());
791 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
792 emitLocationAndNewLine(op);
796 SmallString<16> portName(legalName);
797 portName.push_back(
'.');
798 unsigned baseLen = portName.size();
799 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
800 portName.append(legalize(op.getPortName(i)));
801 addValueName(op.getResult(i), portName);
802 portName.resize(baseLen);
806 void Emitter::emitStatement(AttachOp op) {
807 emitStatementFunctionOp(
PPExtString(
"attach"), op);
810 void Emitter::emitStatement(MemOp op) {
811 auto legalName = legalize(op.getNameAttr());
812 SmallString<16> portName(legalName);
813 portName.push_back(
'.');
814 auto portNameBaseLen = portName.size();
815 for (
auto result : llvm::zip(op.getResults(), op.getPortNames())) {
816 portName.resize(portNameBaseLen);
817 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
818 addValueName(std::get<0>(result), portName);
823 emitLocationAndNewLine(op);
826 ps <<
"data-type => ";
827 emitType(op.getDataType());
832 ps <<
"read-latency => ";
835 ps <<
"write-latency => ";
839 SmallString<16> reader, writer, readwriter;
840 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
841 auto add = [&](SmallString<16> &to, StringAttr name) {
844 to.append(name.getValue());
846 switch (port.second) {
847 case MemOp::PortKind::Read:
848 add(reader, legalize(port.first));
850 case MemOp::PortKind::Write:
851 add(writer, legalize(port.first));
853 case MemOp::PortKind::ReadWrite:
854 add(readwriter, legalize(port.first));
856 case MemOp::PortKind::Debug:
857 emitOpError(op,
"has unsupported 'debug' port");
862 ps <<
"reader => " << reader << PP::newline;
864 ps <<
"writer => " << writer << PP::newline;
865 if (!readwriter.empty())
866 ps <<
"readwriter => " << readwriter << PP::newline;
868 ps <<
"read-under-write => ";
869 emitAttribute(op.getRuw());
874 void Emitter::emitStatement(SeqMemOp op) {
877 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
878 emitTypeWithColon(op.getType());
880 emitAttribute(op.getRuw());
882 emitLocationAndNewLine(op);
885 void Emitter::emitStatement(CombMemOp op) {
888 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
889 emitTypeWithColon(op.getType());
891 emitLocationAndNewLine(op);
894 void Emitter::emitStatement(MemoryPortOp op) {
896 addValueName(op.getData(), legalize(op.getNameAttr()));
899 void Emitter::emitStatement(MemoryDebugPortOp op) {
901 addValueName(op.getData(), legalize(op.getNameAttr()));
904 void Emitter::emitStatement(MemoryPortAccessOp op) {
908 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
909 emitAttribute(port.getDirection());
911 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
914 auto *mem = port.getMemory().getDefiningOp();
915 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
916 ps << legalize(seqMem.getNameAttr());
918 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
922 emitExpression(op.getIndex());
926 emitExpression(op.getClock());
928 emitLocationAndNewLine(op);
931 void Emitter::emitStatement(RefDefineOp op) {
933 emitAssignLike([&]() { emitExpression(op.getDest()); },
934 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
936 emitLocationAndNewLine(op);
939 void Emitter::emitStatement(RefForceOp op) {
943 void Emitter::emitStatement(RefForceInitialOp op) {
945 auto constantPredicate =
946 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
947 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
950 emitExpression(op.getPredicate());
951 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
953 ps <<
"force_initial(";
955 interleaveComma({op.getDest(), op.getSrc()});
960 emitLocationAndNewLine(op);
963 void Emitter::emitStatement(RefReleaseOp op) {
964 emitStatementFunctionOp(
PPExtString(
"release"), op);
967 void Emitter::emitStatement(RefReleaseInitialOp op) {
969 auto constantPredicate =
970 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
971 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
974 emitExpression(op.getPredicate());
975 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
977 ps <<
"release_initial(";
978 emitExpression(op.getDest());
982 emitLocationAndNewLine(op);
985 void Emitter::emitStatement(GroupOp op) {
987 ps <<
"group " << op.getGroupName().getLeafReference() <<
" :";
988 emitLocationAndNewLine(op);
989 auto *body = op.getBody();
990 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
993 void Emitter::emitStatement(InvalidValueOp op) {
996 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
997 return use.getOperandNumber() == 1 &&
998 isa<ConnectOp, StrictConnectOp>(use.getOwner());
1004 auto name = circuitNamespace.newName(
"_invalid");
1005 addValueName(op, name);
1007 emitType(op.getType());
1008 emitLocationAndNewLine(op);
1014 emitLocationAndNewLine(op);
1017 void Emitter::emitExpression(Value value) {
1020 if (
auto name = lookupEmittedName(value)) {
1026 auto op = value.getDefiningOp();
1027 assert(op &&
"value must either be a block arg or the result of an op");
1028 TypeSwitch<Operation *>(op)
1031 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1032 OpenSubfieldOp, OpenSubindexOp,
1034 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1035 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1036 EQPrimOp, NEQPrimOp, CatPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1038 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsClockPrimOp,
1039 CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp, XorRPrimOp,
1041 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1042 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1043 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1046 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp>(
1048 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1050 .Default([&](
auto op) {
1051 emitOpError(op,
"not supported as expression");
1052 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1057 void Emitter::emitExpression(ConstantOp op) {
1059 emitType(op.getType(),
false);
1066 void Emitter::emitExpression(SpecialConstantOp op) {
1067 auto emitInner = [&]() {
1074 .
Case<ClockType>([&](
auto type) {
1079 .Case<ResetType>([&](
auto type) { emitInner(); })
1080 .Case<AsyncResetType>([&](
auto type) {
1081 ps <<
"asAsyncReset(";
1088 void Emitter::emitExpression(SubfieldOp op) {
1089 BundleType type = op.getInput().getType();
1090 emitExpression(op.getInput());
1091 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1095 void Emitter::emitExpression(SubindexOp op) {
1096 emitExpression(op.getInput());
1103 void Emitter::emitExpression(SubaccessOp op) {
1104 emitExpression(op.getInput());
1106 emitExpression(op.getIndex());
1110 void Emitter::emitExpression(OpenSubfieldOp op) {
1111 auto type = op.getInput().getType();
1112 emitExpression(op.getInput());
1113 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1116 void Emitter::emitExpression(OpenSubindexOp op) {
1117 emitExpression(op.getInput());
1123 void Emitter::emitExpression(RefSendOp op) {
1125 emitExpression(op.getBase());
1129 void Emitter::emitExpression(RefResolveOp op) {
1131 emitExpression(op.getRef());
1135 void Emitter::emitExpression(RefSubOp op) {
1136 emitExpression(op.getInput());
1138 .
Case<FVectorType>([&](
auto type) {
1144 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1147 void Emitter::emitExpression(RWProbeOp op) {
1151 auto target = symInfos->get().irn.lookup(op.getTarget());
1153 if (target.isPort()) {
1154 auto mod = cast<FModuleOp>(target.getOp());
1155 auto port = target.getPort();
1156 base = mod.getArgument(port);
1158 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1161 emitExpression(base);
1164 auto fieldID = target.getField();
1165 auto type = base.getType();
1168 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1169 auto index = vecTy.getIndexForFieldID(fieldID);
1173 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1175 fieldID = subfieldID;
1177 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1178 auto index = bundleTy.getIndexForFieldID(fieldID);
1179 ps <<
"." << bundleTy.getElementName(index);
1180 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1182 fieldID = subfieldID;
1188 void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1190 void Emitter::emitExpression(UninferredResetCastOp op) {
1191 emitExpression(op.getInput());
1194 void Emitter::emitExpression(FIntegerConstantOp op) {
1200 void Emitter::emitExpression(BoolConstantOp op) {
1201 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1204 void Emitter::emitExpression(DoubleConstantOp op) {
1210 SmallString<16> str;
1211 op.getValueAttr().getValue().toString(str);
1216 void Emitter::emitExpression(StringConstantOp op) {
1222 void Emitter::emitExpression(ListCreateOp op) {
1223 return emitLiteralExpression(op.getType(), op.getElements());
1226 void Emitter::emitExpression(UnresolvedPathOp op) {
1232 void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1234 void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1235 ArrayRef<uint32_t> attrs) {
1236 ps << mnemonic <<
"(" << PP::ibox0;
1237 interleaveComma(op->getOperands());
1238 if (!op->getOperands().empty() && !attrs.empty())
1239 ps <<
"," << PP::space;
1240 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1241 ps <<
")" << PP::end;
1244 void Emitter::emitAttribute(MemDirAttr attr) {
1246 case MemDirAttr::Infer:
1249 case MemDirAttr::Read:
1252 case MemDirAttr::Write:
1255 case MemDirAttr::ReadWrite:
1261 void Emitter::emitAttribute(RUWAttr attr) {
1263 case RUWAttr::Undefined:
1276 void Emitter::emitType(Type type,
bool includeConst) {
1277 if (includeConst &&
isConst(type))
1279 auto emitWidth = [&](std::optional<int32_t>
width) {
1288 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1289 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1290 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1291 .Case<UIntType>([&](
auto type) {
1293 emitWidth(type.getWidth());
1295 .Case<SIntType>([&](
auto type) {
1297 emitWidth(type.getWidth());
1299 .Case<AnalogType>([&](
auto type) {
1301 emitWidth(type.getWidth());
1303 .Case<OpenBundleType, BundleType>([&](
auto type) {
1305 if (!type.getElements().empty())
1307 bool anyEmitted =
false;
1309 for (
auto &element : type.getElements()) {
1311 ps <<
"," << PP::space;
1312 ps.scopedBox(PP::ibox2, [&]() {
1315 ps << legalize(element.name);
1316 emitTypeWithColon(element.type);
1325 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1326 emitType(type.getElementType());
1331 .Case<RefType>([&](RefType type) {
1332 if (type.getForceable())
1335 emitType(type.getType());
1338 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1339 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1340 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1341 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1342 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1343 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1344 .Case<ListType>([&](ListType type) {
1346 emitType(type.getElementType());
1349 .Default([&](
auto type) {
1350 llvm_unreachable(
"all types should be implemented");
1356 void Emitter::emitLocation(Location loc) {
1358 ps << PP::neverbreak;
1359 if (
auto fileLoc = loc->dyn_cast_or_null<FileLineColLoc>()) {
1360 ps <<
" @[" << fileLoc.getFilename().getValue();
1361 if (
auto line = fileLoc.getLine()) {
1364 if (
auto col = fileLoc.getColumn()) {
1381 std::optional<size_t> targetLineLength,
1383 Emitter emitter(os, version,
1384 targetLineLength.value_or(defaultTargetLineLength));
1385 for (
auto &op : *module.getBody()) {
1386 if (
auto circuitOp = dyn_cast<CircuitOp>(op))
1387 emitter.emitCircuit(circuitOp);
1389 return emitter.finalize();
1394 "target-line-length",
1395 llvm::cl::desc(
"Target line length for emitted .fir"),
1396 llvm::cl::value_desc(
"number of chars"),
1397 llvm::cl::init(defaultTargetLineLength));
1398 static mlir::TranslateFromMLIRRegistration toFIR(
1399 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
1400 [](ModuleOp module, llvm::raw_ostream &os) {
1403 [](mlir::DialectRegistry ®istry) {
1404 registry.insert<chirrtl::CHIRRTLDialect>();
1405 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.
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)
void registerToFIRFileTranslation()
constexpr FIRVersion latestFIRVersion(3, 2, 0)
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.