21#include "mlir/IR/BuiltinOps.h"
22#include "mlir/Tools/mlir-translate/Translation.h"
23#include "llvm/ADT/APSInt.h"
24#include "llvm/ADT/StringSet.h"
25#include "llvm/ADT/TypeSwitch.h"
26#include "llvm/Support/Debug.h"
28#define DEBUG_TYPE "export-firrtl"
31using namespace firrtl;
32using namespace chirrtl;
33using namespace pretty;
42constexpr size_t defaultTargetLineLength = 80;
46 Emitter(llvm::raw_ostream &os,
FIRVersion version,
47 size_t targetLineLength = defaultTargetLineLength)
48 : pp(os, targetLineLength), ps(pp, saver), version(version) {
49 pp.setListener(&saver);
51 LogicalResult finalize();
54 void emitCircuit(CircuitOp op);
55 void emitModule(FModuleOp op);
56 void emitModule(FExtModuleOp op);
57 void emitModule(FIntModuleOp op);
58 void emitModulePorts(ArrayRef<PortInfo> ports,
59 Block::BlockArgListType arguments = {});
60 void emitModuleParameters(Operation *op, ArrayAttr parameters);
61 void emitDeclaration(DomainOp op);
62 void emitDeclaration(LayerOp op);
63 void emitDeclaration(OptionOp op);
64 void emitDeclaration(FormalOp op);
65 void emitDeclaration(SimulationOp op);
66 void emitFormalLike(Operation *op, StringRef keyword, StringAttr symName,
67 StringAttr moduleName, DictionaryAttr params);
68 void emitEnabledLayers(ArrayRef<Attribute> layers);
69 void emitKnownLayers(ArrayRef<Attribute> layers);
70 void emitParamAssign(ParamDeclAttr param, Operation *op,
71 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
72 void emitParamValue(Attribute value, Operation *op);
74 void emitGenericIntrinsic(GenericIntrinsicOp op);
77 void emitStatementsInBlock(
Block &block);
78 void emitStatement(WhenOp op);
79 void emitStatement(WireOp op);
80 void emitStatement(RegOp op);
81 void emitStatement(RegResetOp op);
82 void emitStatement(NodeOp op);
83 void emitStatement(StopOp op);
84 void emitStatement(SkipOp op);
85 void emitFormatString(Operation *op, StringRef formatString, OperandRange ops,
86 llvm::SmallVectorImpl<Value> &substitutions);
88 void emitPrintfLike(T op, StringAttr fileName);
89 void emitStatement(PrintFOp op);
90 void emitStatement(FPrintFOp op);
91 void emitStatement(FFlushOp op);
92 void emitStatement(ConnectOp op);
93 void emitStatement(MatchingConnectOp op);
94 void emitStatement(PropAssignOp op);
95 void emitStatement(InstanceOp op);
96 void emitStatement(InstanceChoiceOp op);
97 void emitStatement(AttachOp op);
98 void emitStatement(MemOp op);
99 void emitStatement(InvalidValueOp op);
100 void emitStatement(CombMemOp op);
101 void emitStatement(SeqMemOp op);
102 void emitStatement(MemoryPortOp op);
103 void emitStatement(MemoryDebugPortOp op);
104 void emitStatement(MemoryPortAccessOp op);
105 void emitStatement(DomainDefineOp op);
106 void emitStatement(RefDefineOp op);
107 void emitStatement(RefForceOp op);
108 void emitStatement(RefForceInitialOp op);
109 void emitStatement(RefReleaseOp op);
110 void emitStatement(RefReleaseInitialOp op);
111 void emitStatement(LayerBlockOp op);
112 void emitStatement(GenericIntrinsicOp op);
115 void emitVerifStatement(T op, StringRef mnemonic);
116 void emitStatement(AssertOp op) { emitVerifStatement(op,
"assert"); }
117 void emitStatement(AssumeOp op) { emitVerifStatement(op,
"assume"); }
118 void emitStatement(CoverOp op) { emitVerifStatement(op,
"cover"); }
121 void emitExpression(Value value);
122 void emitExpression(ConstantOp op);
123 void emitExpression(SpecialConstantOp op);
124 void emitExpression(SubfieldOp op);
125 void emitExpression(SubindexOp op);
126 void emitExpression(SubaccessOp op);
127 void emitExpression(OpenSubfieldOp op);
128 void emitExpression(OpenSubindexOp op);
129 void emitExpression(RefResolveOp op);
130 void emitExpression(RefSendOp op);
131 void emitExpression(RefSubOp op);
132 void emitExpression(RWProbeOp op);
133 void emitExpression(RefCastOp op);
134 void emitExpression(UninferredResetCastOp op);
135 void emitExpression(ConstCastOp op);
136 void emitExpression(StringConstantOp op);
137 void emitExpression(FIntegerConstantOp op);
138 void emitExpression(BoolConstantOp op);
139 void emitExpression(DoubleConstantOp op);
140 void emitExpression(ListCreateOp op);
141 void emitExpression(UnresolvedPathOp op);
142 void emitExpression(GenericIntrinsicOp op);
143 void emitExpression(CatPrimOp op);
144 void emitExpression(UnsafeDomainCastOp op);
146 void emitPrimExpr(StringRef mnemonic, Operation *op,
147 ArrayRef<uint32_t> attrs = {});
149 void emitExpression(BitsPrimOp op) {
150 emitPrimExpr(
"bits", op, {op.getHi(), op.getLo()});
152 void emitExpression(HeadPrimOp op) {
153 emitPrimExpr(
"head", op, op.getAmount());
155 void emitExpression(TailPrimOp op) {
156 emitPrimExpr(
"tail", op, op.getAmount());
158 void emitExpression(PadPrimOp op) { emitPrimExpr(
"pad", op, op.getAmount()); }
159 void emitExpression(ShlPrimOp op) { emitPrimExpr(
"shl", op, op.getAmount()); }
160 void emitExpression(ShrPrimOp op) { emitPrimExpr(
"shr", op, op.getAmount()); }
162 void emitExpression(TimeOp op){};
165#define HANDLE(OPTYPE, MNEMONIC) \
166 void emitExpression(OPTYPE op) { emitPrimExpr(MNEMONIC, op); }
181 HANDLE(DShlPrimOp,
"dshl");
182 HANDLE(DShlwPrimOp,
"dshlw");
183 HANDLE(DShrPrimOp,
"dshr");
185 HANDLE(AsSIntPrimOp,
"asSInt");
186 HANDLE(AsUIntPrimOp,
"asUInt");
187 HANDLE(AsAsyncResetPrimOp,
"asAsyncReset");
188 HANDLE(AsClockPrimOp,
"asClock");
192 HANDLE(AndRPrimOp,
"andr");
194 HANDLE(XorRPrimOp,
"xorr");
198 void emitAttribute(MemDirAttr attr);
199 void emitAttribute(RUWBehaviorAttr attr);
202 void emitType(Type type,
bool includeConst =
true);
203 void emitTypeWithColon(Type type) {
204 ps << PP::space <<
":" << PP::nbsp;
209 void emitDomains(Attribute domains,
210 const DenseMap<size_t, StringRef> &domainMap);
213 void emitLocation(Location loc);
214 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
215 template <
typename... Args>
216 void emitLocationAndNewLine(Args... args) {
219 ps << PP::neverbreak;
220 emitLocation(args...);
224 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
225 llvm::function_ref<
void()> emitRHS,
227 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
229 ps.scopedBox(PP::ibox2, [&]() {
231 ps << *wordBeforeLHS << PP::space;
235 ps << PP::space << syntax << PP::nbsp;
237 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
242 void emitSubExprIBox2(Value v) {
243 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
248 template <
typename Container,
typename EachFn>
249 void interleaveComma(
const Container &c, EachFn eachFn) {
250 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
255 void interleaveComma(ValueRange ops) {
256 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
259 void emitStatementFunctionOp(
PPExtString name, Operation *op) {
262 ps.scopedBox(PP::ibox0, [&]() {
263 interleaveComma(op->getOperands());
266 emitLocationAndNewLine(op);
269 template <
typename EachFn,
typename Range>
270 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
273 ps.scopedBox(PP::ibox0, [&]() {
274 interleaveComma(r, eachFn);
279 void emitLiteralExpression(Type type, ValueRange values) {
280 return emitLiteralExpression(type, values,
281 [&](Value v) { emitSubExprIBox2(v); });
285 void emitSymbol(SymbolRefAttr symbol) {
286 ps.ibox(2, IndentStyle::Block);
287 ps << symbol.getRootReference();
288 for (
auto nested : symbol.getNestedReferences()) {
291 ps << nested.getAttr();
298 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
299 encounteredError =
true;
300 return op->emitError(message);
304 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
305 encounteredError =
true;
306 return op->emitOpError(message);
311 std::optional<StringRef> lookupEmittedName(Value value) {
312 auto it = valueNames.find(value);
313 if (it != valueNames.end())
320 void emitPendingNewlineIfNeeded() {
321 if (pendingNewline) {
322 pendingNewline =
false;
326 void setPendingNewline() {
328 pendingNewline =
true;
331 void startStatement() { emitPendingNewlineIfNeeded(); }
349 bool pendingNewline =
false;
352 bool encounteredError =
false;
357 DenseMap<Value, StringRef> valueNames;
358 StringSet<> valueNamesStorage;
362 StringAttr legalize(StringAttr attr) {
363 StringRef str = attr.getValue();
364 if (str.empty() || !
isdigit(str.front()))
366 return StringAttr::get(attr.getContext(),
"`" + Twine(attr) +
"`");
369 void addValueName(Value value, StringAttr attr) {
370 valueNames.insert({value, attr.getValue()});
372 void addValueName(Value value, StringRef str) {
373 auto it = valueNamesStorage.insert(str);
374 valueNames.insert({value, it.first->getKey()});
376 void addForceable(Forceable op, StringAttr attr) {
377 addValueName(op.getData(), attr);
378 if (op.isForceable()) {
379 SmallString<32> rwName;
380 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
381 addValueName(op.getDataRef(), rwName);
390 SymbolTable symbolTable;
393 SymInfos(Operation *op) : symbolTable(op), istc(op){};
395 std::optional<std::reference_wrapper<SymInfos>> symInfos;
402LogicalResult Emitter::finalize() {
return failure(encounteredError); }
405void Emitter::emitCircuit(CircuitOp op) {
406 circuitNamespace.add(op);
407 SymInfos circuitSymInfos(op);
408 symInfos = circuitSymInfos;
410 ps <<
"FIRRTL version ";
417 ps <<
"circuit " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
421 if (encounteredError)
423 TypeSwitch<Operation *>(&bodyOp)
424 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](
auto op) {
428 .Case<DomainOp, LayerOp, OptionOp, FormalOp, SimulationOp>(
429 [&](
auto op) { emitDeclaration(op); })
430 .Default([&](
auto op) {
431 emitOpError(op,
"not supported for emission inside circuit");
435 circuitNamespace.clear();
436 symInfos = std::nullopt;
439void Emitter::emitEnabledLayers(ArrayRef<Attribute> layers) {
440 for (
auto layer : layers) {
442 ps.
cbox(2, IndentStyle::Block);
443 ps <<
"enablelayer" << PP::space;
444 emitSymbol(cast<SymbolRefAttr>(layer));
449void Emitter::emitKnownLayers(ArrayRef<Attribute> layers) {
450 for (
auto layer : layers) {
452 ps.
cbox(2, IndentStyle::Block);
453 ps <<
"knownlayer" << PP::space;
454 emitSymbol(cast<SymbolRefAttr>(layer));
459void Emitter::emitParamAssign(ParamDeclAttr param, Operation *op,
460 std::optional<PPExtString> wordBeforeLHS) {
462 ps << *wordBeforeLHS << PP::nbsp;
464 ps <<
PPExtString(param.getName().strref()) << PP::nbsp <<
"=" << PP::nbsp;
465 emitParamValue(param.getValue(), op);
468void Emitter::emitParamValue(Attribute value, Operation *op) {
469 TypeSwitch<Attribute>(value)
470 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
471 .Case<FloatAttr>([&](
auto attr) {
473 attr.getValue().toString(str);
478 .Case<ArrayAttr>([&](
auto attr) {
481 interleaveComma(attr.getValue(),
482 [&](
auto element) { emitParamValue(element, op); });
486 .Case<DictionaryAttr>([&](
auto attr) {
489 interleaveComma(attr.getValue(), [&](
auto field) {
490 ps << PPExtString(field.getName()) << PP::nbsp <<
"=" << PP::nbsp;
491 emitParamValue(field.getValue(), op);
496 .Default([&](
auto attr) {
497 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
498 ps <<
"<unsupported-attr ";
504void Emitter::emitGenericIntrinsic(GenericIntrinsicOp op) {
508 ps << op.getIntrinsic();
510 auto params = op.getParameters();
511 if (!params.empty()) {
513 ps.scopedBox(PP::ibox0, [&]() {
515 params.getAsRange<ParamDeclAttr>(),
516 [&](ParamDeclAttr param) { emitParamAssign(param, op); });
521 if (op.getNumResults() != 0)
522 emitTypeWithColon(op.getResult().getType());
524 if (op.getNumOperands() != 0) {
525 ps <<
"," << PP::space;
526 ps.
scopedBox(PP::ibox0, [&]() { interleaveComma(op->getOperands()); });
533void Emitter::emitModule(FModuleOp op) {
535 ps.
cbox(4, IndentStyle::Block);
537 ps <<
"public" << PP::nbsp;
538 ps <<
"module " <<
PPExtString(legalize(op.getNameAttr()));
539 emitEnabledLayers(op.getLayers());
540 ps << PP::nbsp <<
":" << PP::end;
547 auto ports = op.getPorts();
548 emitModulePorts(ports, op.getArguments());
549 if (!ports.empty() && !op.getBodyBlock()->empty())
553 emitStatementsInBlock(*op.getBodyBlock());
556 valueNamesStorage.clear();
560void Emitter::emitModule(FExtModuleOp op) {
562 ps.
cbox(4, IndentStyle::Block);
563 ps <<
"extmodule " <<
PPExtString(legalize(op.getNameAttr()));
564 emitKnownLayers(op.getKnownLayers());
565 emitEnabledLayers(op.getLayers());
566 ps << PP::nbsp <<
":" << PP::end;
573 auto ports = op.getPorts();
574 emitModulePorts(ports);
577 if (op.getDefname() && !op.getDefname()->empty()) {
579 ps <<
"defname = " <<
PPExtString(*op.getDefname());
584 emitModuleParameters(op, op.getParameters());
589void Emitter::emitModule(FIntModuleOp op) {
591 ps.
cbox(4, IndentStyle::Block);
592 ps <<
"intmodule " <<
PPExtString(legalize(op.getNameAttr()));
593 emitEnabledLayers(op.getLayers());
594 ps << PP::nbsp <<
":" << PP::end;
601 auto ports = op.getPorts();
602 emitModulePorts(ports);
605 ps <<
"intrinsic = " <<
PPExtString(op.getIntrinsic());
609 emitModuleParameters(op, op.getParameters());
616void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
617 Block::BlockArgListType arguments) {
618 DenseMap<size_t, StringRef> domainMap;
619 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
621 const auto &port = ports[i];
622 ps << (port.direction == Direction::In ?
"input " :
"output ");
623 auto legalName = legalize(port.name);
624 if (isa<DomainType>(port.type))
625 domainMap.insert({i, port.name});
626 if (!arguments.empty())
627 addValueName(arguments[i], legalName);
630 emitDomains(port.domains, domainMap);
631 emitLocation(ports[i].loc);
636void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
637 for (
auto param : parameters.getAsRange<ParamDeclAttr>()) {
639 emitParamAssign(param, op,
PPExtString(
"parameter"));
644void Emitter::emitDeclaration(DomainOp op) {
646 ps <<
"domain " <<
PPExtString(op.getSymName()) <<
" :";
647 emitLocationAndNewLine(op);
649 for (
auto attr : op.getFields()) {
650 auto fieldAttr = cast<DomainFieldAttr>(attr);
651 ps << PP::newline <<
PPExtString(fieldAttr.getName()) <<
" : ";
652 emitType(fieldAttr.getType());
658void Emitter::emitDeclaration(LayerOp op) {
660 ps <<
"layer " <<
PPExtString(op.getSymName()) <<
", "
661 <<
PPExtString(stringifyLayerConvention(op.getConvention()));
663 if (
auto outputFile = op->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
669 emitLocationAndNewLine(op);
671 for (
auto &bodyOp : op.getBody().getOps()) {
672 TypeSwitch<Operation *>(&bodyOp)
673 .Case<LayerOp>([&](
auto op) { emitDeclaration(op); })
674 .Default([&](
auto op) {
676 "not supported for emission inside layer definition");
683void Emitter::emitDeclaration(OptionOp op) {
685 ps <<
"option " <<
PPExtString(legalize(op.getSymNameAttr())) <<
" :";
688 for (
auto caseOp : op.getBody().getOps<OptionCaseOp>()) {
690 ps <<
PPExtString(legalize(caseOp.getSymNameAttr()));
691 emitLocation(caseOp);
694 ps << PP::newline << PP::newline;
698void Emitter::emitDeclaration(FormalOp op) {
699 emitFormalLike(op,
"formal", op.getSymNameAttr(),
700 op.getModuleNameAttr().getAttr(), op.getParameters());
704void Emitter::emitDeclaration(SimulationOp op) {
705 emitFormalLike(op,
"simulation", op.getSymNameAttr(),
706 op.getModuleNameAttr().getAttr(), op.getParameters());
710void Emitter::emitFormalLike(Operation *op, StringRef keyword,
711 StringAttr symName, StringAttr moduleName,
712 DictionaryAttr params) {
714 ps.
cbox(4, IndentStyle::Block);
715 ps << keyword <<
" " <<
PPExtString(legalize(symName));
717 ps << PP::nbsp <<
":" << PP::end;
722 for (
auto param : params) {
724 ps <<
PPExtString(param.getName()) << PP::nbsp <<
"=" << PP::nbsp;
725 emitParamValue(param.getValue(), op);
739 return (
isExpression(op) && !isa<InvalidValueOp>(op)) ||
740 (isa<GenericIntrinsicOp>(op) && op->hasOneUse() &&
744void Emitter::emitStatementsInBlock(Block &block) {
745 for (
auto &bodyOp : block) {
746 if (encounteredError)
750 TypeSwitch<Operation *>(&bodyOp)
751 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
752 PrintFOp, FPrintFOp, FFlushOp, AssertOp, AssumeOp, CoverOp,
753 ConnectOp, MatchingConnectOp, PropAssignOp, InstanceOp,
754 InstanceChoiceOp, AttachOp, MemOp, InvalidValueOp, SeqMemOp,
755 CombMemOp, MemoryPortOp, MemoryDebugPortOp, MemoryPortAccessOp,
756 DomainDefineOp, RefDefineOp, RefForceOp, RefForceInitialOp,
757 RefReleaseOp, RefReleaseInitialOp, LayerBlockOp,
758 GenericIntrinsicOp>([&](
auto op) { emitStatement(op); })
759 .Default([&](
auto op) {
761 ps <<
"// operation " <<
PPExtString(op->getName().getStringRef());
763 emitOpError(op,
"not supported as statement");
768void Emitter::emitStatement(WhenOp op) {
771 emitExpression(op.getCondition());
773 emitLocationAndNewLine(op);
774 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
776 if (!op.hasElseRegion())
783 auto &elseBlock = op.getElseBlock();
784 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
785 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
786 emitStatement(whenOp);
793 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
796void Emitter::emitStatement(WireOp op) {
797 auto legalName = legalize(op.getNameAttr());
798 addForceable(op, legalName);
802 emitTypeWithColon(op.getResult().getType());
804 emitLocationAndNewLine(op);
807void Emitter::emitStatement(RegOp op) {
808 auto legalName = legalize(op.getNameAttr());
809 addForceable(op, legalName);
813 emitTypeWithColon(op.getResult().getType());
814 ps <<
"," << PP::space;
815 emitExpression(op.getClockVal());
817 emitLocationAndNewLine(op);
820void Emitter::emitStatement(RegResetOp op) {
821 auto legalName = legalize(op.getNameAttr());
822 addForceable(op, legalName);
826 ps <<
"regreset " << legalName;
827 emitTypeWithColon(op.getResult().getType());
828 ps <<
"," << PP::space;
829 emitExpression(op.getClockVal());
830 ps <<
"," << PP::space;
831 emitExpression(op.getResetSignal());
832 ps <<
"," << PP::space;
833 emitExpression(op.getResetValue());
837 ps <<
"reg " << legalName;
838 emitTypeWithColon(op.getResult().getType());
839 ps <<
"," << PP::space;
840 emitExpression(op.getClockVal());
841 ps << PP::space <<
"with :";
843 ps << PP::neverbreak;
846 ps <<
"reset => (" << PP::ibox0;
847 emitExpression(op.getResetSignal());
848 ps <<
"," << PP::space;
849 emitExpression(op.getResetValue());
850 ps <<
")" << PP::end;
853 emitLocationAndNewLine(op);
856void Emitter::emitStatement(NodeOp op) {
857 auto legalName = legalize(op.getNameAttr());
858 addForceable(op, legalName);
860 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(legalName); },
861 [&]() { emitExpression(op.getInput()); });
862 emitLocationAndNewLine(op);
865void Emitter::emitStatement(StopOp op) {
868 ps <<
"stop(" << PP::ibox0;
869 emitExpression(op.getClock());
870 ps <<
"," << PP::space;
871 emitExpression(op.getCond());
872 ps <<
"," << PP::space;
874 ps <<
")" << PP::end;
875 if (!op.getName().empty()) {
876 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
879 emitLocationAndNewLine(op);
882void Emitter::emitStatement(SkipOp op) {
885 emitLocationAndNewLine(op);
888void Emitter::emitFormatString(Operation *op, StringRef origFormatString,
889 OperandRange substitutionOperands,
890 llvm::SmallVectorImpl<Value> &substitutions) {
899 SmallString<64> formatString;
900 for (
size_t i = 0, e = origFormatString.size(), opIdx = 0; i != e; ++i) {
901 auto c = origFormatString[i];
904 formatString.push_back(c);
907 SmallString<6> width;
908 c = origFormatString[++i];
911 c = origFormatString[++i];
920 formatString.append(width);
923 substitutions.push_back(substitutionOperands[opIdx++]);
926 formatString.push_back(c);
931 if (origFormatString.slice(i, i + 4) ==
"{{}}") {
932 formatString.append(
"{{");
933 TypeSwitch<Operation *>(substitutionOperands[opIdx++].getDefiningOp())
935 [&](
auto time) { formatString.append(
"SimulationTime"); })
936 .Case<HierarchicalModuleNameOp>([&](
auto time) {
937 formatString.append(
"HierarchicalModuleName");
940 emitError(op,
"unsupported fstring substitution type");
942 formatString.append(
"}}");
947 formatString.push_back(c);
953void Emitter::emitStatement(PrintFOp op) {
956 ps <<
"printf(" << PP::ibox0;
957 emitExpression(op.getClock());
958 ps <<
"," << PP::space;
959 emitExpression(op.getCond());
960 ps <<
"," << PP::space;
962 SmallVector<Value, 4> substitutions;
963 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
965 for (
auto operand : substitutions) {
966 ps <<
"," << PP::space;
967 emitExpression(operand);
969 ps <<
")" << PP::end;
970 if (!op.getName().empty()) {
971 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
974 emitLocationAndNewLine(op);
977void Emitter::emitStatement(FPrintFOp op) {
980 ps <<
"fprintf(" << PP::ibox0;
981 emitExpression(op.getClock());
982 ps <<
"," << PP::space;
983 emitExpression(op.getCond());
984 ps <<
"," << PP::space;
986 SmallVector<Value, 4> outputFileSubstitutions;
987 emitFormatString(op, op.getOutputFile(), op.getOutputFileSubstitutions(),
988 outputFileSubstitutions);
989 if (!outputFileSubstitutions.empty()) {
990 ps <<
"," << PP::space;
991 interleaveComma(outputFileSubstitutions);
994 ps <<
"," << PP::space;
995 SmallVector<Value, 4> substitutions;
996 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
998 if (!substitutions.empty()) {
999 ps <<
"," << PP::space;
1000 interleaveComma(substitutions);
1003 ps <<
")" << PP::end;
1004 if (!op.getName().empty()) {
1005 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1008 emitLocationAndNewLine(op);
1011void Emitter::emitStatement(FFlushOp op) {
1014 ps <<
"fflush(" << PP::ibox0;
1015 emitExpression(op.getClock());
1016 ps <<
"," << PP::space;
1017 emitExpression(op.getCond());
1018 if (op.getOutputFileAttr()) {
1019 ps <<
"," << PP::space;
1020 SmallVector<Value, 4> substitutions;
1021 emitFormatString(op, op.getOutputFileAttr(),
1022 op.getOutputFileSubstitutions(), substitutions);
1023 if (!substitutions.empty()) {
1024 ps <<
"," << PP::space;
1025 interleaveComma(substitutions);
1028 ps <<
")" << PP::end;
1030 emitLocationAndNewLine(op);
1034void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
1037 ps << mnemonic <<
"(" << PP::ibox0;
1038 emitExpression(op.getClock());
1039 ps <<
"," << PP::space;
1040 emitExpression(op.getPredicate());
1041 ps <<
"," << PP::space;
1042 emitExpression(op.getEnable());
1043 ps <<
"," << PP::space;
1045 ps <<
")" << PP::end;
1046 if (!op.getName().empty()) {
1047 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1050 emitLocationAndNewLine(op);
1053void Emitter::emitStatement(ConnectOp op) {
1057 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1058 ps <<
"invalidate" << PP::space;
1059 emitExpression(op.getDest());
1061 ps <<
"connect" << PP::space;
1062 emitExpression(op.getDest());
1063 ps <<
"," << PP::space;
1064 emitExpression(op.getSrc());
1068 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1069 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1071 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1074 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1077 emitLocationAndNewLine(op);
1080void Emitter::emitStatement(MatchingConnectOp op) {
1084 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1085 ps <<
"invalidate" << PP::space;
1086 emitExpression(op.getDest());
1088 ps <<
"connect" << PP::space;
1089 emitExpression(op.getDest());
1090 ps <<
"," << PP::space;
1091 emitExpression(op.getSrc());
1095 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1096 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1098 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1101 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1104 emitLocationAndNewLine(op);
1107void Emitter::emitStatement(PropAssignOp op) {
1110 ps <<
"propassign" << PP::space;
1111 interleaveComma(op.getOperands());
1113 emitLocationAndNewLine(op);
1116void Emitter::emitStatement(InstanceOp op) {
1118 auto legalName = legalize(op.getNameAttr());
1120 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
1121 emitLocationAndNewLine(op);
1125 SmallString<16> portName(legalName);
1126 portName.push_back(
'.');
1127 unsigned baseLen = portName.size();
1128 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1129 portName.append(legalize(op.getPortNameAttr(i)));
1130 addValueName(op.getResult(i), portName);
1131 portName.resize(baseLen);
1135void Emitter::emitStatement(InstanceChoiceOp op) {
1137 auto legalName = legalize(op.getNameAttr());
1138 ps <<
"instchoice " <<
PPExtString(legalName) <<
" of "
1139 <<
PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
1140 <<
PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
1143 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
1145 ps <<
PPExtString(legalize(optSym.getLeafReference()));
1150 setPendingNewline();
1152 SmallString<16> portName(legalName);
1153 portName.push_back(
'.');
1154 unsigned baseLen = portName.size();
1155 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1156 portName.append(legalize(op.getPortNameAttr(i)));
1157 addValueName(op.getResult(i), portName);
1158 portName.resize(baseLen);
1162void Emitter::emitStatement(AttachOp op) {
1163 emitStatementFunctionOp(
PPExtString(
"attach"), op);
1166void Emitter::emitStatement(MemOp op) {
1167 auto legalName = legalize(op.getNameAttr());
1168 SmallString<16> portName(legalName);
1169 portName.push_back(
'.');
1170 auto portNameBaseLen = portName.size();
1171 for (
auto result :
llvm::zip(op.getResults(), op.getPortNames())) {
1172 portName.resize(portNameBaseLen);
1173 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
1174 addValueName(std::get<0>(result), portName);
1179 emitLocationAndNewLine(op);
1182 ps <<
"data-type => ";
1183 emitType(op.getDataType());
1188 ps <<
"read-latency => ";
1191 ps <<
"write-latency => ";
1195 SmallString<16> reader, writer, readwriter;
1196 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
1197 auto add = [&](SmallString<16> &to, StringAttr name) {
1200 to.append(name.getValue());
1202 switch (port.second) {
1203 case MemOp::PortKind::Read:
1204 add(reader, legalize(port.first));
1206 case MemOp::PortKind::Write:
1207 add(writer, legalize(port.first));
1209 case MemOp::PortKind::ReadWrite:
1210 add(readwriter, legalize(port.first));
1212 case MemOp::PortKind::Debug:
1213 emitOpError(op,
"has unsupported 'debug' port");
1217 if (!reader.empty())
1218 ps <<
"reader => " << reader << PP::newline;
1219 if (!writer.empty())
1220 ps <<
"writer => " << writer << PP::newline;
1221 if (!readwriter.empty())
1222 ps <<
"readwriter => " << readwriter << PP::newline;
1224 ps <<
"read-under-write => ";
1225 emitAttribute(op.getRuwAttr());
1226 setPendingNewline();
1230void Emitter::emitStatement(SeqMemOp op) {
1233 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
1234 emitTypeWithColon(op.getType());
1235 ps <<
"," << PP::space;
1236 emitAttribute(op.getRuwAttr());
1238 emitLocationAndNewLine(op);
1241void Emitter::emitStatement(CombMemOp op) {
1244 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
1245 emitTypeWithColon(op.getType());
1247 emitLocationAndNewLine(op);
1250void Emitter::emitStatement(MemoryPortOp op) {
1252 addValueName(op.getData(), legalize(op.getNameAttr()));
1255void Emitter::emitStatement(MemoryDebugPortOp op) {
1257 addValueName(op.getData(), legalize(op.getNameAttr()));
1260void Emitter::emitStatement(MemoryPortAccessOp op) {
1264 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1265 emitAttribute(port.getDirection());
1267 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
1270 auto *mem = port.getMemory().getDefiningOp();
1271 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1272 ps << legalize(seqMem.getNameAttr());
1274 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1278 emitExpression(op.getIndex());
1282 emitExpression(op.getClock());
1284 emitLocationAndNewLine(op);
1287void Emitter::emitStatement(DomainDefineOp op) {
1289 emitAssignLike([&]() { emitExpression(op.getDest()); },
1290 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1292 emitLocationAndNewLine(op);
1295void Emitter::emitStatement(RefDefineOp op) {
1297 emitAssignLike([&]() { emitExpression(op.getDest()); },
1298 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1300 emitLocationAndNewLine(op);
1303void Emitter::emitStatement(RefForceOp op) {
1304 emitStatementFunctionOp(
PPExtString(
"force"), op);
1307void Emitter::emitStatement(RefForceInitialOp op) {
1309 auto constantPredicate =
1310 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1311 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1314 emitExpression(op.getPredicate());
1315 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1317 ps <<
"force_initial(";
1319 interleaveComma({op.getDest(), op.getSrc()});
1324 emitLocationAndNewLine(op);
1327void Emitter::emitStatement(RefReleaseOp op) {
1328 emitStatementFunctionOp(
PPExtString(
"release"), op);
1331void Emitter::emitStatement(RefReleaseInitialOp op) {
1333 auto constantPredicate =
1334 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1335 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1338 emitExpression(op.getPredicate());
1339 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1341 ps <<
"release_initial(";
1342 emitExpression(op.getDest());
1346 emitLocationAndNewLine(op);
1349void Emitter::emitStatement(LayerBlockOp op) {
1351 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1352 emitLocationAndNewLine(op);
1353 auto *body = op.getBody();
1354 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1357void Emitter::emitStatement(InvalidValueOp op) {
1360 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1361 return use.getOperandNumber() == 1 &&
1362 isa<ConnectOp, MatchingConnectOp>(use.getOwner());
1368 auto name = circuitNamespace.newName(
"_invalid");
1369 addValueName(op, name);
1371 emitType(op.getType());
1372 emitLocationAndNewLine(op);
1378 emitLocationAndNewLine(op);
1381void Emitter::emitStatement(GenericIntrinsicOp op) {
1384 emitGenericIntrinsic(op);
1387 auto name = circuitNamespace.newName(
"_gen_int");
1388 addValueName(op.getResult(), name);
1389 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(name); },
1390 [&]() { emitGenericIntrinsic(op); });
1392 emitLocationAndNewLine(op);
1395void Emitter::emitExpression(Value value) {
1398 if (
auto name = lookupEmittedName(value)) {
1404 auto op = value.getDefiningOp();
1405 assert(op &&
"value must either be a block arg or the result of an op");
1406 TypeSwitch<Operation *>(op)
1409 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1410 OpenSubfieldOp, OpenSubindexOp,
1412 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1413 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1414 EQPrimOp, NEQPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1416 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsClockPrimOp,
1417 CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp, XorRPrimOp,
1419 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1420 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1421 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1422 UnresolvedPathOp, GenericIntrinsicOp, CatPrimOp, UnsafeDomainCastOp,
1424 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp,
1426 TimeOp>([&](
auto op) {
1427 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1429 .Default([&](
auto op) {
1430 emitOpError(op,
"not supported as expression");
1431 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1436void Emitter::emitExpression(ConstantOp op) {
1438 emitType(op.getType(),
false);
1445void Emitter::emitExpression(SpecialConstantOp op) {
1446 auto emitInner = [&]() {
1453 .
Case<ClockType>([&](
auto type) {
1458 .Case<ResetType>([&](
auto type) { emitInner(); })
1459 .Case<AsyncResetType>([&](
auto type) {
1460 ps <<
"asAsyncReset(";
1467void Emitter::emitExpression(SubfieldOp op) {
1468 BundleType type = op.getInput().getType();
1469 emitExpression(op.getInput());
1470 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1474void Emitter::emitExpression(SubindexOp op) {
1475 emitExpression(op.getInput());
1482void Emitter::emitExpression(SubaccessOp op) {
1483 emitExpression(op.getInput());
1485 emitExpression(op.getIndex());
1489void Emitter::emitExpression(OpenSubfieldOp op) {
1490 auto type = op.getInput().getType();
1491 emitExpression(op.getInput());
1492 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1495void Emitter::emitExpression(OpenSubindexOp op) {
1496 emitExpression(op.getInput());
1502void Emitter::emitExpression(RefSendOp op) {
1504 emitExpression(op.getBase());
1508void Emitter::emitExpression(RefResolveOp op) {
1510 emitExpression(op.getRef());
1514void Emitter::emitExpression(RefSubOp op) {
1515 emitExpression(op.getInput());
1517 .
Case<FVectorType>([&](
auto type) {
1523 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1526void Emitter::emitExpression(RWProbeOp op) {
1530 auto target = symInfos->get().irn.lookup(op.getTarget());
1532 if (target.isPort()) {
1533 auto mod = cast<FModuleOp>(target.getOp());
1534 auto port = target.getPort();
1535 base = mod.getArgument(port);
1537 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1540 emitExpression(base);
1543 auto fieldID = target.getField();
1544 auto type = base.getType();
1547 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1548 auto index = vecTy.getIndexForFieldID(fieldID);
1552 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1554 fieldID = subfieldID;
1556 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1557 auto index = bundleTy.getIndexForFieldID(fieldID);
1558 ps <<
"." << bundleTy.getElementName(index);
1559 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1561 fieldID = subfieldID;
1567void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1569void Emitter::emitExpression(UninferredResetCastOp op) {
1570 emitExpression(op.getInput());
1573void Emitter::emitExpression(FIntegerConstantOp op) {
1579void Emitter::emitExpression(BoolConstantOp op) {
1580 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1583void Emitter::emitExpression(DoubleConstantOp op) {
1589 SmallString<16> str;
1590 op.getValueAttr().getValue().toString(str);
1595void Emitter::emitExpression(StringConstantOp op) {
1601void Emitter::emitExpression(ListCreateOp op) {
1602 return emitLiteralExpression(op.getType(), op.getElements());
1605void Emitter::emitExpression(UnresolvedPathOp op) {
1611void Emitter::emitExpression(GenericIntrinsicOp op) {
1612 emitGenericIntrinsic(op);
1615void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1617void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1618 ArrayRef<uint32_t> attrs) {
1619 ps << mnemonic <<
"(" << PP::ibox0;
1620 interleaveComma(op->getOperands());
1621 if (!op->getOperands().empty() && !attrs.empty())
1622 ps <<
"," << PP::space;
1623 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1624 ps <<
")" << PP::end;
1627void Emitter::emitExpression(CatPrimOp op) {
1628 size_t numOperands = op.getNumOperands();
1629 switch (numOperands) {
1632 emitType(op.getType(),
false);
1636 auto operand = op->getOperand(0);
1638 if (isa<UIntType>(operand.getType()))
1639 return emitExpression(operand);
1642 ps <<
"cat(" << PP::ibox0;
1643 emitExpression(op->getOperand(0));
1644 ps <<
"," << PP::space <<
"SInt<0>(0))" << PP::end;
1650 for (
size_t i = 0; i < numOperands - 1; ++i) {
1651 ps <<
"cat(" << PP::ibox0;
1652 emitExpression(op->getOperand(i));
1653 ps <<
"," << PP::space;
1656 emitExpression(op->getOperand(numOperands - 1));
1657 for (
size_t i = 0; i < numOperands - 1; ++i)
1658 ps <<
")" << PP::end;
1663void Emitter::emitExpression(UnsafeDomainCastOp op) {
1664 ps <<
"unsafe_domain_cast(" << PP::ibox0;
1665 interleaveComma(op.getOperands(),
1666 [&](Value operand) { emitExpression(operand); });
1667 ps <<
")" << PP::end;
1670void Emitter::emitAttribute(MemDirAttr attr) {
1672 case MemDirAttr::Infer:
1675 case MemDirAttr::Read:
1678 case MemDirAttr::Write:
1681 case MemDirAttr::ReadWrite:
1687void Emitter::emitAttribute(RUWBehaviorAttr attr) {
1688 switch (attr.getValue()) {
1689 case RUWBehavior::Undefined:
1692 case RUWBehavior::Old:
1695 case RUWBehavior::New:
1702void Emitter::emitType(Type type,
bool includeConst) {
1703 if (includeConst &&
isConst(type))
1705 auto emitWidth = [&](std::optional<int32_t> width) {
1714 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1715 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1716 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1717 .Case<UIntType>([&](
auto type) {
1719 emitWidth(type.getWidth());
1721 .Case<SIntType>([&](
auto type) {
1723 emitWidth(type.getWidth());
1725 .Case<AnalogType>([&](
auto type) {
1727 emitWidth(type.getWidth());
1729 .Case<OpenBundleType, BundleType>([&](
auto type) {
1731 if (!type.getElements().empty())
1733 bool anyEmitted =
false;
1735 for (
auto &element : type.getElements()) {
1737 ps <<
"," << PP::space;
1741 ps << legalize(element.name);
1742 emitTypeWithColon(element.type);
1751 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1752 emitType(type.getElementType());
1757 .Case<RefType>([&](RefType type) {
1758 if (type.getForceable())
1761 ps.
cbox(2, IndentStyle::Block);
1763 emitType(type.getType());
1764 if (
auto layer = type.getLayer()) {
1767 emitSymbol(type.getLayer());
1772 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1773 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1774 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1775 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1776 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1777 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1778 .Case<ListType>([&](ListType type) {
1780 emitType(type.getElementType());
1783 .Case<DomainType>([&](DomainType type) { ps <<
"Domain"; })
1784 .Default([&](
auto type) {
1785 llvm_unreachable(
"all types should be implemented");
1789void Emitter::emitDomains(Attribute attr,
1790 const DenseMap<size_t, StringRef> &domainMap) {
1793 if (
auto domains = dyn_cast<ArrayAttr>(attr)) {
1794 if (domains.empty())
1798 interleaveComma(domains, [&](Attribute attr) {
1799 auto itr = domainMap.find(cast<IntegerAttr>(attr).getUInt());
1800 assert(itr != domainMap.end() &&
"Unable to find domain");
1806 auto kind = cast<FlatSymbolRefAttr>(attr);
1813void Emitter::emitLocation(Location loc) {
1815 ps << PP::neverbreak;
1817 dyn_cast_or_null<FileLineColLoc, LocationAttr>(LocationAttr(loc))) {
1818 ps <<
" @[" << fileLoc.getFilename().getValue();
1819 if (
auto line = fileLoc.getLine()) {
1822 if (
auto col = fileLoc.getColumn()) {
1839 std::optional<size_t> targetLineLength,
1841 Emitter emitter(os, version,
1842 targetLineLength.value_or(defaultTargetLineLength));
1843 for (
auto &op : *
module.getBody()) {
1844 if (auto circuitOp = dyn_cast<CircuitOp>(op))
1845 emitter.emitCircuit(circuitOp);
1847 return emitter.finalize();
1852 "target-line-length",
1853 llvm::cl::desc(
"Target line length for emitted .fir"),
1854 llvm::cl::value_desc(
"number of chars"),
1855 llvm::cl::init(defaultTargetLineLength));
1856 static mlir::TranslateFromMLIRRegistration toFIR(
1857 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
1858 [](ModuleOp module, llvm::raw_ostream &os) {
1861 [](mlir::DialectRegistry ®istry) {
1862 registry.insert<chirrtl::CHIRRTLDialect>();
1863 registry.insert<firrtl::FIRRTLDialect>();
assert(baseType &&"element must be base type")
#define HANDLE(OPTYPE, OPKIND)
static bool isEmittedInline(Operation *op)
Check if an operation is inlined into the emission of their users.
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Block * getBodyBlock(FModuleLike mod)
This class implements the same functionality as TypeSwitch except that it uses firrtl::type_dyn_cast ...
FIRRTLTypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
This class represents a collection of InnerSymbolTable's.
void space()
Add a breakable space.
void cbox(int32_t offset=0, IndentStyle style=IndentStyle::Visual)
Start a consistent group with specified offset.
void zerobreak()
Add a break that is zero-wide if not broken.
Wrap a PrettyPrinter with TokenBuilder features as well as operator<<'s.
auto scopedBox(T &&t, Callable &&c, Token close=EndToken())
Open a box, invoke the lambda, and close it after.
TokenStream & addAsString(T &&t)
General-purpose "format this" helper, for types not supported by operator<< yet.
TokenStream & writeQuotedEscaped(StringRef str, bool useHexEscapes=false, StringRef left="\"", StringRef right="\"")
PrettyPrinter::Listener that saves strings while live.
mlir::LogicalResult exportFIRFile(mlir::ModuleOp module, llvm::raw_ostream &os, std::optional< size_t > targetLineLength, FIRVersion version)
constexpr FIRVersion exportFIRVersion
The version of FIRRTL that the exporter produces.
void registerToFIRFileTranslation()
bool isConst(Type type)
Returns true if this is a 'const' type whose value is guaranteed to be unchanging at circuit executio...
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
The namespace of a CircuitOp, generally inhabited by modules.
The FIRRTL specification version.
This class represents the namespace in which InnerRef's can be resolved.
String wrapper to indicate string has external storage.