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"
42constexpr size_t defaultTargetLineLength = 80;
46 Emitter(llvm::raw_ostream &os,
FIRVersion version,
47 size_t targetLineLength = defaultTargetLineLength)
48 : pp(os, targetLineLength), ps(pp, saver), version(version) {
49 pp.setListener(&saver);
51 LogicalResult finalize();
54 void emitCircuit(CircuitOp op);
55 void emitModule(FModuleOp op);
56 void emitModule(FExtModuleOp op);
57 void emitModule(FIntModuleOp op);
58 void emitModulePorts(ArrayRef<PortInfo> ports,
59 Block::BlockArgListType arguments = {});
60 void emitModuleParameters(Operation *op, ArrayAttr parameters);
61 void emitDeclaration(DomainOp op);
62 void emitDeclaration(LayerOp op);
63 void emitDeclaration(OptionOp op);
64 void emitDeclaration(FormalOp op);
65 void emitDeclaration(SimulationOp op);
66 void emitFormalLike(Operation *op, StringRef keyword, StringAttr symName,
67 StringAttr moduleName, DictionaryAttr params);
68 void emitEnabledLayers(ArrayRef<Attribute> layers, Operation *op);
69 void emitKnownLayers(ArrayRef<Attribute> layers, Operation *op);
70 void emitRequirements(ArrayRef<Attribute> requirements);
71 void emitParamAssign(ParamDeclAttr param, Operation *op,
72 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
73 void emitParamValue(Attribute value, Operation *op);
75 void emitGenericIntrinsic(GenericIntrinsicOp op);
78 void emitStatementsInBlock(
Block &block);
79 void emitStatement(WhenOp op);
80 void emitStatement(WireOp op);
81 void emitStatement(RegOp op);
82 void emitStatement(RegResetOp op);
83 void emitStatement(NodeOp op);
84 void emitStatement(StopOp op);
85 void emitStatement(SkipOp op);
86 void emitFormatString(Operation *op, StringRef formatString, OperandRange ops,
87 llvm::SmallVectorImpl<Value> &substitutions);
89 void emitPrintfLike(T op, StringAttr fileName);
90 void emitStatement(PrintFOp op);
91 void emitStatement(FPrintFOp op);
92 void emitStatement(FFlushOp op);
93 void emitStatement(ConnectOp op);
94 void emitStatement(MatchingConnectOp op);
95 void emitStatement(PropertyAssertOp op);
96 void emitStatement(PropAssignOp op);
97 void emitStatement(InstanceOp op);
98 void emitStatement(InstanceChoiceOp op);
99 void emitStatement(AttachOp op);
100 void emitStatement(MemOp op);
101 void emitStatement(InvalidValueOp op);
102 void emitStatement(CombMemOp op);
103 void emitStatement(SeqMemOp op);
104 void emitStatement(MemoryPortOp op);
105 void emitStatement(MemoryDebugPortOp op);
106 void emitStatement(MemoryPortAccessOp op);
107 void emitStatement(DomainDefineOp op);
108 void emitStatement(RefDefineOp op);
109 void emitStatement(RefForceOp op);
110 void emitStatement(RefForceInitialOp op);
111 void emitStatement(RefReleaseOp op);
112 void emitStatement(RefReleaseInitialOp op);
113 void emitStatement(LayerBlockOp op);
114 void emitStatement(GenericIntrinsicOp op);
115 void emitStatement(DomainCreateAnonOp op);
116 void emitStatement(DomainCreateOp op);
119 void emitVerifStatement(T op, StringRef mnemonic);
120 void emitStatement(AssertOp op) { emitVerifStatement(op,
"assert"); }
121 void emitStatement(AssumeOp op) { emitVerifStatement(op,
"assume"); }
122 void emitStatement(CoverOp op) { emitVerifStatement(op,
"cover"); }
125 void emitExpression(Value value);
126 void emitExpression(ConstantOp op);
127 void emitExpression(SpecialConstantOp op);
128 void emitExpression(SubfieldOp op);
129 void emitExpression(SubindexOp op);
130 void emitExpression(SubaccessOp op);
131 void emitExpression(OpenSubfieldOp op);
132 void emitExpression(DomainSubfieldOp op);
133 void emitExpression(OpenSubindexOp op);
134 void emitExpression(DomainAnyRefCastOp op);
135 void emitExpression(RefResolveOp op);
136 void emitExpression(RefSendOp op);
137 void emitExpression(RefSubOp op);
138 void emitExpression(RWProbeOp op);
139 void emitExpression(RefCastOp op);
140 void emitExpression(UninferredResetCastOp op);
141 void emitExpression(ConstCastOp op);
142 void emitExpression(StringConstantOp op);
143 void emitExpression(FIntegerConstantOp op);
144 void emitExpression(BoolConstantOp op);
145 void emitExpression(DoubleConstantOp op);
146 void emitExpression(ListCreateOp op);
147 void emitExpression(UnresolvedPathOp op);
148 void emitExpression(GenericIntrinsicOp op);
149 void emitExpression(CatPrimOp op);
150 void emitExpression(UnsafeDomainCastOp op);
151 void emitExpression(UnknownValueOp op);
153 void emitPrimExpr(StringRef mnemonic, Operation *op,
154 ArrayRef<uint32_t>
attrs = {});
156 void emitExpression(BitsPrimOp op) {
157 emitPrimExpr(
"bits", op, {op.getHi(), op.getLo()});
159 void emitExpression(HeadPrimOp op) {
160 emitPrimExpr(
"head", op, op.getAmount());
162 void emitExpression(TailPrimOp op) {
163 emitPrimExpr(
"tail", op, op.getAmount());
165 void emitExpression(PadPrimOp op) { emitPrimExpr(
"pad", op, op.getAmount()); }
166 void emitExpression(ShlPrimOp op) { emitPrimExpr(
"shl", op, op.getAmount()); }
167 void emitExpression(ShrPrimOp op) { emitPrimExpr(
"shr", op, op.getAmount()); }
169 void emitExpression(TimeOp op) {}
172#define HANDLE(OPTYPE, MNEMONIC) \
173 void emitExpression(OPTYPE op) { emitPrimExpr(MNEMONIC, op); }
188 HANDLE(DShlPrimOp,
"dshl");
189 HANDLE(DShlwPrimOp,
"dshlw");
190 HANDLE(DShrPrimOp,
"dshr");
192 HANDLE(AsSIntPrimOp,
"asSInt");
193 HANDLE(AsUIntPrimOp,
"asUInt");
194 HANDLE(AsAsyncResetPrimOp,
"asAsyncReset");
195 HANDLE(AsResetPrimOp,
"asReset");
196 HANDLE(AsClockPrimOp,
"asClock");
200 HANDLE(AndRPrimOp,
"andr");
202 HANDLE(XorRPrimOp,
"xorr");
203 HANDLE(StringConcatOp,
"string_concat");
206 void emitExpression(PropEqOp op) {
207 if (failed(requireVersion({6, 0, 0}, op,
"property equality")))
209 emitPrimExpr(
"prop_eq", op);
212 void emitExpression(ObjectEqOp op) {
213 if (failed(requireVersion(
nextFIRVersion, op,
"object equality")))
215 emitPrimExpr(
"object_eq", op);
218 void emitExpression(ListContainsOp op) {
221 emitPrimExpr(
"list_contains", op);
224 void emitExpression(BoolAndOp op) {
225 if (failed(requireVersion({6, 0, 0}, op,
"boolean and")))
227 emitPrimExpr(
"bool_and", op);
230 void emitExpression(BoolOrOp op) {
231 if (failed(requireVersion({6, 0, 0}, op,
"boolean or")))
233 emitPrimExpr(
"bool_or", op);
236 void emitExpression(BoolXorOp op) {
237 if (failed(requireVersion({6, 0, 0}, op,
"boolean xor")))
239 emitPrimExpr(
"bool_xor", op);
242 void emitExpression(IntegerAndOp op) {
245 emitPrimExpr(
"integer_and", op);
248 void emitExpression(IntegerOrOp op) {
251 emitPrimExpr(
"integer_or", op);
254 void emitExpression(IntegerNotOp op) {
257 emitPrimExpr(
"integer_not", op);
261 void emitAttribute(MemDirAttr attr);
262 void emitAttribute(RUWBehaviorAttr attr);
265 void emitType(Type type,
bool includeConst =
true);
266 void emitTypeWithColon(Type type) {
267 ps << PP::space <<
":" << PP::nbsp;
272 void emitDomains(Attribute attr, ArrayRef<PortInfo> ports);
275 void emitLocation(Location loc);
276 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
277 template <
typename... Args>
278 void emitLocationAndNewLine(Args... args) {
281 ps << PP::neverbreak;
282 emitLocation(args...);
286 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
287 llvm::function_ref<
void()> emitRHS,
288 PPExtString syntax = PPExtString(
"="),
289 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
291 ps.scopedBox(PP::ibox2, [&]() {
293 ps << *wordBeforeLHS << PP::space;
297 ps << PP::space << syntax << PP::nbsp;
299 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
304 void emitSubExprIBox2(Value v) {
305 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
310 template <
typename Container,
typename EachFn>
311 void interleaveComma(
const Container &c, EachFn eachFn) {
312 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
317 void interleaveComma(ValueRange ops) {
318 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
321 void emitStatementFunctionOp(PPExtString name, Operation *op) {
324 ps.scopedBox(PP::ibox0, [&]() {
325 interleaveComma(op->getOperands());
328 emitLocationAndNewLine(op);
331 template <
typename EachFn,
typename Range>
332 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
335 ps.scopedBox(PP::ibox0, [&]() {
336 interleaveComma(r, eachFn);
341 void emitLiteralExpression(Type type, ValueRange values) {
342 return emitLiteralExpression(type, values,
343 [&](Value v) { emitSubExprIBox2(v); });
347 void emitSymbol(SymbolRefAttr symbol) {
348 ps.ibox(2, IndentStyle::Block);
349 ps << symbol.getRootReference();
350 for (
auto nested : symbol.getNestedReferences()) {
353 ps << nested.getAttr();
360 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
361 encounteredError =
true;
362 return op->emitError(message);
366 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
367 encounteredError =
true;
368 return op->emitOpError(message);
372 LogicalResult requireVersion(FIRVersion minVersion, Operation *op,
374 if (version >= minVersion)
377 return emitOpError(op, feature +
" requires FIRRTL ") << minVersion;
382 std::optional<StringRef> lookupEmittedName(Value value) {
383 auto it = valueNames.find(value);
384 if (it != valueNames.end())
391 void emitPendingNewlineIfNeeded() {
392 if (pendingNewline) {
393 pendingNewline =
false;
397 void setPendingNewline() {
399 pendingNewline =
true;
402 void startStatement() { emitPendingNewlineIfNeeded(); }
407 TokenStringSaver saver;
420 bool pendingNewline =
false;
423 bool encounteredError =
false;
428 DenseMap<Value, StringRef> valueNames;
429 StringSet<> valueNamesStorage;
433 StringAttr legalize(StringAttr attr) {
434 StringRef str = attr.getValue();
435 if (str.empty() || !
isdigit(str.front()))
437 return StringAttr::get(attr.getContext(),
"`" + Twine(attr) +
"`");
440 void addValueName(Value value, StringAttr attr) {
441 valueNames.insert({value, attr.getValue()});
443 void addValueName(Value value, StringRef str) {
444 auto it = valueNamesStorage.insert(str);
445 valueNames.insert({value, it.first->getKey()});
447 void addForceable(Forceable op, StringAttr attr) {
448 addValueName(op.getData(), attr);
449 if (op.isForceable()) {
450 SmallString<32> rwName;
451 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
452 addValueName(op.getDataRef(), rwName);
457 CircuitNamespace circuitNamespace;
461 SymbolTable symbolTable;
462 hw::InnerSymbolTableCollection istc;
463 hw::InnerRefNamespace irn{symbolTable, istc};
464 SymInfos(Operation *op) : symbolTable(op), istc(op) {}
466 std::optional<std::reference_wrapper<SymInfos>> symInfos;
473LogicalResult Emitter::finalize() {
return failure(encounteredError); }
476void Emitter::emitCircuit(CircuitOp op) {
477 circuitNamespace.add(op);
478 SymInfos circuitSymInfos(op);
479 symInfos = circuitSymInfos;
481 ps <<
"FIRRTL version ";
488 ps <<
"circuit " << PPExtString(legalize(op.getNameAttr())) <<
" :";
491 for (
auto &bodyOp : *op.getBodyBlock()) {
492 if (encounteredError)
494 TypeSwitch<Operation *>(&bodyOp)
495 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](
auto op) {
499 .Case<DomainOp, LayerOp, OptionOp, FormalOp, SimulationOp>(
500 [&](
auto op) { emitDeclaration(op); })
501 .Default([&](
auto op) {
502 emitOpError(op,
"not supported for emission inside circuit");
506 circuitNamespace.clear();
507 symInfos = std::nullopt;
510void Emitter::emitEnabledLayers(ArrayRef<Attribute> layers, Operation *op) {
513 if (failed(requireVersion(FIRVersion(4, 0, 0), op,
"enabled layers")))
515 for (
auto layer : layers) {
517 ps.
cbox(2, IndentStyle::Block);
518 ps <<
"enablelayer" << PP::space;
519 emitSymbol(cast<SymbolRefAttr>(layer));
524void Emitter::emitKnownLayers(ArrayRef<Attribute> layers, Operation *op) {
527 if (failed(requireVersion({6, 0, 0}, op,
"known layers")))
529 for (
auto layer : layers) {
531 ps.
cbox(2, IndentStyle::Block);
532 ps <<
"knownlayer" << PP::space;
533 emitSymbol(cast<SymbolRefAttr>(layer));
538void Emitter::emitRequirements(ArrayRef<Attribute> requirements) {
539 if (requirements.empty())
542 ps.
cbox(2, IndentStyle::Block);
543 ps <<
"requires" << PP::space;
544 llvm::interleaveComma(requirements, ps, [&](Attribute req) {
550void Emitter::emitParamAssign(ParamDeclAttr param, Operation *op,
551 std::optional<PPExtString> wordBeforeLHS) {
553 ps << *wordBeforeLHS << PP::nbsp;
555 ps << PPExtString(param.getName().strref()) << PP::nbsp <<
"=" << PP::nbsp;
556 emitParamValue(param.getValue(), op);
559void Emitter::emitParamValue(Attribute value, Operation *op) {
560 TypeSwitch<Attribute>(value)
561 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
562 .Case<FloatAttr>([&](
auto attr) {
564 attr.getValue().toString(str);
569 .Case<ArrayAttr>([&](
auto attr) {
572 interleaveComma(attr.getValue(),
573 [&](
auto element) { emitParamValue(element, op); });
577 .Case<DictionaryAttr>([&](
auto attr) {
580 interleaveComma(attr.getValue(), [&](
auto field) {
581 ps << PPExtString(field.getName()) << PP::nbsp <<
"=" << PP::nbsp;
582 emitParamValue(field.getValue(), op);
587 .Default([&](
auto attr) {
588 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
589 ps <<
"<unsupported-attr ";
595void Emitter::emitGenericIntrinsic(GenericIntrinsicOp op) {
599 ps << op.getIntrinsic();
601 auto params = op.getParameters();
602 if (!params.empty()) {
606 params.getAsRange<ParamDeclAttr>(),
607 [&](ParamDeclAttr param) { emitParamAssign(param, op); });
612 if (op.getNumResults() != 0)
613 emitTypeWithColon(op.getResult().getType());
615 if (op.getNumOperands() != 0) {
616 ps <<
"," << PP::space;
617 ps.
scopedBox(PP::ibox0, [&]() { interleaveComma(op->getOperands()); });
624void Emitter::emitModule(FModuleOp op) {
626 ps.
cbox(4, IndentStyle::Block);
627 if (op.isPublic() && FIRVersion(3, 3, 0) <= version)
628 ps <<
"public" << PP::nbsp;
629 ps <<
"module " << PPExtString(legalize(op.getNameAttr()));
630 emitEnabledLayers(op.getLayers(), op);
631 ps << PP::nbsp <<
":" << PP::end;
638 auto ports = op.getPorts();
639 emitModulePorts(ports, op.getArguments());
640 if (!ports.empty() && !op.getBodyBlock()->empty())
644 emitStatementsInBlock(*op.getBodyBlock());
647 valueNamesStorage.clear();
651void Emitter::emitModule(FExtModuleOp op) {
653 ps.
cbox(4, IndentStyle::Block);
654 ps <<
"extmodule " << PPExtString(legalize(op.getNameAttr()));
655 emitKnownLayers(op.getKnownLayers(), op);
656 emitEnabledLayers(op.getLayers(), op);
657 if (
auto reqs = op.getExternalRequirements())
658 emitRequirements(reqs.getValue());
659 ps << PP::nbsp <<
":" << PP::end;
666 auto ports = op.getPorts();
667 emitModulePorts(ports);
670 if (op.getDefname() && !op.getDefname()->empty()) {
672 ps <<
"defname = " << PPExtString(*op.getDefname());
677 emitModuleParameters(op, op.getParameters());
682void Emitter::emitModule(FIntModuleOp op) {
683 if (FIRVersion(4, 0, 0) <= version) {
684 emitOpError(op,
"intrinsic modules were removed in FIRRTL 4.0.0");
688 ps.
cbox(4, IndentStyle::Block);
689 ps <<
"intmodule " << PPExtString(legalize(op.getNameAttr()));
690 emitEnabledLayers(op.getLayers(), op);
691 ps << PP::nbsp <<
":" << PP::end;
698 auto ports = op.getPorts();
699 emitModulePorts(ports);
702 ps <<
"intrinsic = " << PPExtString(op.getIntrinsic());
706 emitModuleParameters(op, op.getParameters());
713void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
714 Block::BlockArgListType arguments) {
716 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
718 const auto &port = ports[i];
719 ps << (port.direction == Direction::In ?
"input " :
"output ");
720 auto legalName = legalize(port.name);
721 if (!arguments.empty())
722 addValueName(arguments[i], legalName);
723 ps << PPExtString(legalName) <<
" : ";
725 emitDomains(port.domains, ports);
726 emitLocation(ports[i].loc);
731void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
732 for (
auto param : parameters.getAsRange<ParamDeclAttr>()) {
734 emitParamAssign(param, op, PPExtString(
"parameter"));
739void Emitter::emitDeclaration(DomainOp op) {
743 ps <<
"domain " << PPExtString(op.getSymName()) <<
" :";
744 emitLocationAndNewLine(op);
746 for (
auto attr : op.getFields()) {
747 auto fieldAttr = cast<DomainFieldAttr>(attr);
748 ps << PP::newline << PPExtString(fieldAttr.getName()) <<
" : ";
749 emitType(fieldAttr.getType());
755void Emitter::emitDeclaration(LayerOp op) {
756 if (failed(requireVersion(FIRVersion(3, 3, 0), op,
"layers")))
758 if (op.getConvention() == LayerConvention::Inline &&
759 failed(requireVersion(FIRVersion(4, 1, 0), op,
"inline layers")))
762 ps <<
"layer " << PPExtString(op.getSymName()) <<
", "
763 << PPExtString(stringifyLayerConvention(op.getConvention()));
765 if (
auto outputFile = op->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
771 emitLocationAndNewLine(op);
773 for (
auto &bodyOp : op.getBody().getOps()) {
774 TypeSwitch<Operation *>(&bodyOp)
775 .Case<LayerOp>([&](
auto op) { emitDeclaration(op); })
776 .Default([&](
auto op) {
778 "not supported for emission inside layer definition");
785void Emitter::emitDeclaration(OptionOp op) {
789 ps <<
"option " << PPExtString(legalize(op.getSymNameAttr())) <<
" :";
792 for (
auto caseOp : op.getBody().getOps<OptionCaseOp>()) {
794 ps << PPExtString(legalize(caseOp.getSymNameAttr()));
795 emitLocation(caseOp);
798 ps << PP::newline << PP::newline;
802void Emitter::emitDeclaration(FormalOp op) {
803 if (failed(requireVersion(FIRVersion(4, 0, 0), op,
"formal tests")))
805 emitFormalLike(op,
"formal", op.getSymNameAttr(),
806 op.getModuleNameAttr().getAttr(), op.getParameters());
810void Emitter::emitDeclaration(SimulationOp op) {
811 if (failed(requireVersion(
nextFIRVersion, op,
"simulation tests")))
813 emitFormalLike(op,
"simulation", op.getSymNameAttr(),
814 op.getModuleNameAttr().getAttr(), op.getParameters());
818void Emitter::emitFormalLike(Operation *op, StringRef keyword,
819 StringAttr symName, StringAttr moduleName,
820 DictionaryAttr params) {
822 ps.
cbox(4, IndentStyle::Block);
823 ps << keyword <<
" " << PPExtString(legalize(symName));
824 ps <<
" of " << PPExtString(legalize(moduleName));
825 ps << PP::nbsp <<
":" << PP::end;
830 for (
auto param : params) {
832 ps << PPExtString(param.getName()) << PP::nbsp <<
"=" << PP::nbsp;
833 emitParamValue(param.getValue(), op);
847 return (
isExpression(op) && !isa<InvalidValueOp>(op)) ||
848 (isa<GenericIntrinsicOp>(op) && op->hasOneUse() &&
852void Emitter::emitStatementsInBlock(
Block &block) {
853 for (
auto &bodyOp : block) {
854 if (encounteredError)
858 TypeSwitch<Operation *>(&bodyOp)
859 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
860 PrintFOp, FPrintFOp, FFlushOp, AssertOp, AssumeOp, CoverOp,
861 ConnectOp, MatchingConnectOp, PropertyAssertOp, PropAssignOp,
862 InstanceOp, InstanceChoiceOp, AttachOp, MemOp, InvalidValueOp,
863 SeqMemOp, CombMemOp, MemoryPortOp, MemoryDebugPortOp,
864 MemoryPortAccessOp, DomainDefineOp, RefDefineOp, RefForceOp,
865 RefForceInitialOp, RefReleaseOp, RefReleaseInitialOp,
866 LayerBlockOp, GenericIntrinsicOp, DomainCreateAnonOp,
867 DomainCreateOp>([&](
auto op) { emitStatement(op); })
868 .Default([&](
auto op) {
870 ps <<
"// operation " << PPExtString(op->getName().getStringRef());
872 emitOpError(op,
"not supported as statement");
877void Emitter::emitStatement(WhenOp op) {
880 emitExpression(op.getCondition());
882 emitLocationAndNewLine(op);
883 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
885 if (!op.hasElseRegion())
892 auto &elseBlock = op.getElseBlock();
893 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
894 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
895 emitStatement(whenOp);
902 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
905void Emitter::emitStatement(WireOp op) {
906 auto legalName = legalize(op.getNameAttr());
907 addForceable(op, legalName);
910 ps <<
"wire " << PPExtString(legalName);
911 emitTypeWithColon(op.getResult().getType());
914 if (!op.getDomains().empty()) {
915 ps << PP::space <<
"domains" << PP::space <<
"[";
917 llvm::interleaveComma(op.getDomains(), ps, [&](Value domain) {
918 auto name = lookupEmittedName(domain);
919 assert(name &&
"domain value must have a name");
920 ps << PPExtString(*name);
926 emitLocationAndNewLine(op);
929void Emitter::emitStatement(RegOp op) {
930 auto legalName = legalize(op.getNameAttr());
931 addForceable(op, legalName);
934 ps <<
"reg " << PPExtString(legalName);
935 emitTypeWithColon(op.getResult().getType());
936 ps <<
"," << PP::space;
937 emitExpression(op.getClockVal());
939 emitLocationAndNewLine(op);
942void Emitter::emitStatement(RegResetOp op) {
943 auto legalName = legalize(op.getNameAttr());
944 addForceable(op, legalName);
946 if (FIRVersion(3, 0, 0) <= version) {
948 ps <<
"regreset " << legalName;
949 emitTypeWithColon(op.getResult().getType());
950 ps <<
"," << PP::space;
951 emitExpression(op.getClockVal());
952 ps <<
"," << PP::space;
953 emitExpression(op.getResetSignal());
954 ps <<
"," << PP::space;
955 emitExpression(op.getResetValue());
959 ps <<
"reg " << legalName;
960 emitTypeWithColon(op.getResult().getType());
961 ps <<
"," << PP::space;
962 emitExpression(op.getClockVal());
963 ps << PP::space <<
"with :";
965 ps << PP::neverbreak;
968 ps <<
"reset => (" << PP::ibox0;
969 emitExpression(op.getResetSignal());
970 ps <<
"," << PP::space;
971 emitExpression(op.getResetValue());
972 ps <<
")" << PP::end;
975 emitLocationAndNewLine(op);
978void Emitter::emitStatement(NodeOp op) {
979 auto legalName = legalize(op.getNameAttr());
980 addForceable(op, legalName);
982 emitAssignLike([&]() { ps <<
"node " << PPExtString(legalName); },
983 [&]() { emitExpression(op.getInput()); });
984 emitLocationAndNewLine(op);
987void Emitter::emitStatement(StopOp op) {
990 ps <<
"stop(" << PP::ibox0;
991 emitExpression(op.getClock());
992 ps <<
"," << PP::space;
993 emitExpression(op.getCond());
994 ps <<
"," << PP::space;
996 ps <<
")" << PP::end;
997 if (!op.getName().empty()) {
998 ps << PP::space <<
": " << PPExtString(legalize(op.getNameAttr()));
1001 emitLocationAndNewLine(op);
1004void Emitter::emitStatement(SkipOp op) {
1007 emitLocationAndNewLine(op);
1010void Emitter::emitFormatString(Operation *op, StringRef origFormatString,
1011 OperandRange substitutionOperands,
1012 llvm::SmallVectorImpl<Value> &substitutions) {
1021 SmallString<64> formatString;
1022 for (
size_t i = 0, e = origFormatString.size(), opIdx = 0; i != e; ++i) {
1023 auto c = origFormatString[i];
1026 formatString.push_back(c);
1029 SmallString<6> width;
1030 c = origFormatString[++i];
1033 c = origFormatString[++i];
1042 formatString.append(width);
1045 substitutions.push_back(substitutionOperands[opIdx++]);
1048 formatString.push_back(c);
1053 if (origFormatString.slice(i, i + 4) ==
"{{}}") {
1054 formatString.append(
"{{");
1055 TypeSwitch<Operation *>(substitutionOperands[opIdx++].getDefiningOp())
1057 [&](
auto time) { formatString.append(
"SimulationTime"); })
1058 .Case<HierarchicalModuleNameOp>([&](
auto time) {
1059 formatString.append(
"HierarchicalModuleName");
1061 .Default([&](
auto) {
1062 emitError(op,
"unsupported fstring substitution type");
1064 formatString.append(
"}}");
1069 formatString.push_back(c);
1075void Emitter::emitStatement(PrintFOp op) {
1078 ps <<
"printf(" << PP::ibox0;
1079 emitExpression(op.getClock());
1080 ps <<
"," << PP::space;
1081 emitExpression(op.getCond());
1082 ps <<
"," << PP::space;
1084 SmallVector<Value, 4> substitutions;
1085 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
1087 for (
auto operand : substitutions) {
1088 ps <<
"," << PP::space;
1089 emitExpression(operand);
1091 ps <<
")" << PP::end;
1092 if (!op.getName().empty()) {
1093 ps << PP::space <<
": " << PPExtString(legalize(op.getNameAttr()));
1096 emitLocationAndNewLine(op);
1099void Emitter::emitStatement(FPrintFOp op) {
1100 if (failed(requireVersion({6, 0, 0}, op,
"fprintf")))
1104 ps <<
"fprintf(" << PP::ibox0;
1105 emitExpression(op.getClock());
1106 ps <<
"," << PP::space;
1107 emitExpression(op.getCond());
1108 ps <<
"," << PP::space;
1110 SmallVector<Value, 4> outputFileSubstitutions;
1111 emitFormatString(op, op.getOutputFile(), op.getOutputFileSubstitutions(),
1112 outputFileSubstitutions);
1113 if (!outputFileSubstitutions.empty()) {
1114 ps <<
"," << PP::space;
1115 interleaveComma(outputFileSubstitutions);
1118 ps <<
"," << PP::space;
1119 SmallVector<Value, 4> substitutions;
1120 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
1122 if (!substitutions.empty()) {
1123 ps <<
"," << PP::space;
1124 interleaveComma(substitutions);
1127 ps <<
")" << PP::end;
1128 if (!op.getName().empty()) {
1129 ps << PP::space <<
": " << PPExtString(legalize(op.getNameAttr()));
1132 emitLocationAndNewLine(op);
1135void Emitter::emitStatement(FFlushOp op) {
1136 if (failed(requireVersion({6, 0, 0}, op,
"fflush")))
1140 ps <<
"fflush(" << PP::ibox0;
1141 emitExpression(op.getClock());
1142 ps <<
"," << PP::space;
1143 emitExpression(op.getCond());
1144 if (op.getOutputFileAttr()) {
1145 ps <<
"," << PP::space;
1146 SmallVector<Value, 4> substitutions;
1147 emitFormatString(op, op.getOutputFileAttr(),
1148 op.getOutputFileSubstitutions(), substitutions);
1149 if (!substitutions.empty()) {
1150 ps <<
"," << PP::space;
1151 interleaveComma(substitutions);
1154 ps <<
")" << PP::end;
1156 emitLocationAndNewLine(op);
1160void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
1163 ps << mnemonic <<
"(" << PP::ibox0;
1164 emitExpression(op.getClock());
1165 ps <<
"," << PP::space;
1166 emitExpression(op.getPredicate());
1167 ps <<
"," << PP::space;
1168 emitExpression(op.getEnable());
1169 ps <<
"," << PP::space;
1171 ps <<
")" << PP::end;
1172 if (!op.getName().empty()) {
1173 ps << PP::space <<
": " << PPExtString(legalize(op.getNameAttr()));
1176 emitLocationAndNewLine(op);
1179void Emitter::emitStatement(ConnectOp op) {
1181 if (FIRVersion(3, 0, 0) <= version) {
1183 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1184 ps <<
"invalidate" << PP::space;
1185 emitExpression(op.getDest());
1187 ps <<
"connect" << PP::space;
1188 emitExpression(op.getDest());
1189 ps <<
"," << PP::space;
1190 emitExpression(op.getSrc());
1194 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1195 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1197 emitLHS, [&]() { ps <<
"invalid"; }, PPExtString(
"is"));
1200 emitLHS, [&]() { emitExpression(op.getSrc()); }, PPExtString(
"<="));
1203 emitLocationAndNewLine(op);
1206void Emitter::emitStatement(MatchingConnectOp op) {
1208 if (FIRVersion(3, 0, 0) <= version) {
1210 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1211 ps <<
"invalidate" << PP::space;
1212 emitExpression(op.getDest());
1214 ps <<
"connect" << PP::space;
1215 emitExpression(op.getDest());
1216 ps <<
"," << PP::space;
1217 emitExpression(op.getSrc());
1221 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1222 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1224 emitLHS, [&]() { ps <<
"invalid"; }, PPExtString(
"is"));
1227 emitLHS, [&]() { emitExpression(op.getSrc()); }, PPExtString(
"<="));
1230 emitLocationAndNewLine(op);
1233void Emitter::emitStatement(PropertyAssertOp op) {
1234 if (failed(requireVersion(FIRVersion(6, 0, 0), op,
"property assert")))
1238 ps <<
"propassert" << PP::space;
1239 emitExpression(op.getCondition());
1240 ps <<
"," << PP::space;
1244 if (version < FIRVersion(7, 0, 0)) {
1245 auto expr = dyn_cast<StringConstantOp>(op.getMessage().getDefiningOp());
1248 emitOpError(op,
"unable to emit non-literal string expressions "
1249 "when targeting FIRRTL version <= 7.0.0");
1250 diag.attachNote(op.getMessage().getLoc())
1251 <<
"non-literal expression is here";
1254 emitExpression(op.getMessage());
1257 emitLocationAndNewLine(op);
1260void Emitter::emitStatement(PropAssignOp op) {
1261 if (failed(requireVersion(FIRVersion(3, 1, 0), op,
"properties")))
1265 ps <<
"propassign" << PP::space;
1266 interleaveComma(op.getOperands());
1268 emitLocationAndNewLine(op);
1271void Emitter::emitStatement(InstanceOp op) {
1273 auto legalName = legalize(op.getNameAttr());
1274 ps <<
"inst " << PPExtString(legalName) <<
" of "
1275 << PPExtString(legalize(op.getModuleNameAttr().getAttr()));
1276 emitLocationAndNewLine(op);
1280 SmallString<16> portName(legalName);
1281 portName.push_back(
'.');
1282 unsigned baseLen = portName.size();
1283 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1284 portName.append(legalize(op.getPortNameAttr(i)));
1285 addValueName(op.getResult(i), portName);
1286 portName.resize(baseLen);
1290void Emitter::emitStatement(InstanceChoiceOp op) {
1292 "option groups/instance choices")))
1295 auto legalName = legalize(op.getNameAttr());
1296 ps <<
"instchoice " << PPExtString(legalName) <<
" of "
1297 << PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
1298 << PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
1301 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
1303 ps << PPExtString(legalize(optSym.getLeafReference()));
1305 ps << PPExtString(legalize(targetSym.getAttr()));
1308 setPendingNewline();
1310 SmallString<16> portName(legalName);
1311 portName.push_back(
'.');
1312 unsigned baseLen = portName.size();
1313 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1314 portName.append(legalize(op.getPortNameAttr(i)));
1315 addValueName(op.getResult(i), portName);
1316 portName.resize(baseLen);
1320void Emitter::emitStatement(AttachOp op) {
1321 emitStatementFunctionOp(PPExtString(
"attach"), op);
1324void Emitter::emitStatement(MemOp op) {
1325 auto legalName = legalize(op.getNameAttr());
1326 SmallString<16> portName(legalName);
1327 portName.push_back(
'.');
1328 auto portNameBaseLen = portName.size();
1329 for (
auto result : llvm::zip(op.getResults(), op.getPortNames())) {
1330 portName.resize(portNameBaseLen);
1331 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
1332 addValueName(std::get<0>(result), portName);
1336 ps <<
"mem " << PPExtString(legalName) <<
" :";
1337 emitLocationAndNewLine(op);
1340 ps <<
"data-type => ";
1341 emitType(op.getDataType());
1346 ps <<
"read-latency => ";
1349 ps <<
"write-latency => ";
1353 SmallString<16> reader, writer, readwriter;
1354 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
1355 auto add = [&](SmallString<16> &to, StringAttr name) {
1358 to.append(name.getValue());
1360 switch (port.second) {
1361 case MemOp::PortKind::Read:
1362 add(reader, legalize(port.first));
1364 case MemOp::PortKind::Write:
1365 add(writer, legalize(port.first));
1367 case MemOp::PortKind::ReadWrite:
1368 add(readwriter, legalize(port.first));
1370 case MemOp::PortKind::Debug:
1371 emitOpError(op,
"has unsupported 'debug' port");
1375 if (!reader.empty())
1376 ps <<
"reader => " << reader << PP::newline;
1377 if (!writer.empty())
1378 ps <<
"writer => " << writer << PP::newline;
1379 if (!readwriter.empty())
1380 ps <<
"readwriter => " << readwriter << PP::newline;
1382 ps <<
"read-under-write => ";
1383 emitAttribute(op.getRuwAttr());
1384 setPendingNewline();
1388void Emitter::emitStatement(SeqMemOp op) {
1391 ps <<
"smem " << PPExtString(legalize(op.getNameAttr()));
1392 emitTypeWithColon(op.getType());
1393 ps <<
"," << PP::space;
1394 emitAttribute(op.getRuwAttr());
1396 emitLocationAndNewLine(op);
1399void Emitter::emitStatement(CombMemOp op) {
1402 ps <<
"cmem " << PPExtString(legalize(op.getNameAttr()));
1403 emitTypeWithColon(op.getType());
1405 emitLocationAndNewLine(op);
1408void Emitter::emitStatement(MemoryPortOp op) {
1410 addValueName(op.getData(), legalize(op.getNameAttr()));
1413void Emitter::emitStatement(MemoryDebugPortOp op) {
1415 addValueName(op.getData(), legalize(op.getNameAttr()));
1418void Emitter::emitStatement(MemoryPortAccessOp op) {
1422 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1423 emitAttribute(port.getDirection());
1425 ps <<
" mport " << PPExtString(legalize(port.getNameAttr())) <<
" = ";
1428 auto *mem = port.getMemory().getDefiningOp();
1429 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1430 ps << legalize(seqMem.getNameAttr());
1432 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1436 emitExpression(op.getIndex());
1440 emitExpression(op.getClock());
1442 emitLocationAndNewLine(op);
1445void Emitter::emitStatement(DomainDefineOp op) {
1449 if (isa_and_nonnull<DomainCreateAnonOp>(op.getSrc().getDefiningOp()))
1453 emitAssignLike([&]() { emitExpression(op.getDest()); },
1454 [&]() { emitExpression(op.getSrc()); }, PPExtString(
"="),
1455 PPExtString(
"domain_define"));
1456 emitLocationAndNewLine(op);
1459void Emitter::emitStatement(RefDefineOp op) {
1461 emitAssignLike([&]() { emitExpression(op.getDest()); },
1462 [&]() { emitExpression(op.getSrc()); }, PPExtString(
"="),
1463 PPExtString(
"define"));
1464 emitLocationAndNewLine(op);
1467void Emitter::emitStatement(RefForceOp op) {
1468 emitStatementFunctionOp(PPExtString(
"force"), op);
1471void Emitter::emitStatement(RefForceInitialOp op) {
1473 auto constantPredicate =
1474 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1475 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1478 emitExpression(op.getPredicate());
1479 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1481 ps <<
"force_initial(";
1483 interleaveComma({op.getDest(), op.getSrc()});
1488 emitLocationAndNewLine(op);
1491void Emitter::emitStatement(RefReleaseOp op) {
1492 emitStatementFunctionOp(PPExtString(
"release"), op);
1495void Emitter::emitStatement(RefReleaseInitialOp op) {
1497 auto constantPredicate =
1498 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1499 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1502 emitExpression(op.getPredicate());
1503 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1505 ps <<
"release_initial(";
1506 emitExpression(op.getDest());
1510 emitLocationAndNewLine(op);
1513void Emitter::emitStatement(LayerBlockOp op) {
1514 if (failed(requireVersion(FIRVersion(3, 3, 0), op,
"layers")))
1517 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1518 emitLocationAndNewLine(op);
1519 auto *body = op.getBody();
1520 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1523void Emitter::emitStatement(InvalidValueOp op) {
1526 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1527 return use.getOperandNumber() == 1 &&
1528 isa<ConnectOp, MatchingConnectOp>(use.getOwner());
1534 auto name = circuitNamespace.newName(
"_invalid");
1535 addValueName(op, name);
1536 ps <<
"wire " << PPExtString(name) <<
" : ";
1537 emitType(op.getType());
1538 emitLocationAndNewLine(op);
1540 if (FIRVersion(3, 0, 0) <= version)
1541 ps <<
"invalidate " << PPExtString(name);
1543 ps << PPExtString(name) <<
" is invalid";
1544 emitLocationAndNewLine(op);
1547void Emitter::emitStatement(GenericIntrinsicOp op) {
1548 if (failed(requireVersion(FIRVersion(4, 0, 0), op,
"generic intrinsics")))
1552 emitGenericIntrinsic(op);
1555 auto name = circuitNamespace.newName(
"_gen_int");
1556 addValueName(op.getResult(), name);
1557 emitAssignLike([&]() { ps <<
"node " << PPExtString(name); },
1558 [&]() { emitGenericIntrinsic(op); });
1560 emitLocationAndNewLine(op);
1563void Emitter::emitStatement(DomainCreateAnonOp op) {
1567void Emitter::emitStatement(DomainCreateOp op) {
1571 auto name = legalize(op.getNameAttr());
1572 addValueName(op.getResult(), name);
1574 ps <<
"domain " << PPExtString(name) <<
" of "
1575 << PPExtString(op.getDomainAttr().getValue());
1577 auto fieldValues = op.getFieldValues();
1578 if (fieldValues.empty())
1581 ps <<
"(" << PP::ibox0;
1582 interleaveComma(fieldValues, [&](
auto value) { emitExpression(value); });
1583 ps <<
")" << PP::end;
1586 emitLocationAndNewLine(op);
1589void Emitter::emitExpression(Value value) {
1592 if (
auto name = lookupEmittedName(value)) {
1598 auto *op = value.getDefiningOp();
1599 assert(op &&
"value must either be a block arg or the result of an op");
1600 TypeSwitch<Operation *>(op)
1603 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1604 OpenSubfieldOp, OpenSubindexOp, DomainSubfieldOp,
1606 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1607 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1608 EQPrimOp, NEQPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1610 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsResetPrimOp,
1611 AsClockPrimOp, CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp,
1614 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1615 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1616 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1617 UnresolvedPathOp, GenericIntrinsicOp, CatPrimOp, UnsafeDomainCastOp,
1618 DomainAnyRefCastOp, UnknownValueOp, IntegerAndOp, IntegerOrOp,
1619 IntegerNotOp, StringConcatOp, PropEqOp, ObjectEqOp, ListContainsOp,
1620 BoolAndOp, BoolOrOp, BoolXorOp,
1622 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp,
1624 TimeOp>([&](
auto op) {
1625 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1627 .Default([&](
auto op) {
1628 emitOpError(op,
"not supported as expression");
1629 ps <<
"<unsupported-expr-" << PPExtString(op->getName().stripDialect())
1634void Emitter::emitExpression(ConstantOp op) {
1636 emitType(op.getType(),
false);
1643void Emitter::emitExpression(SpecialConstantOp op) {
1644 auto emitInner = [&]() {
1651 .Case<ClockType>([&](
auto type) {
1656 .Case<ResetType>([&](
auto type) { emitInner(); })
1657 .Case<AsyncResetType>([&](
auto type) {
1658 ps <<
"asAsyncReset(";
1665void Emitter::emitExpression(SubfieldOp op) {
1666 BundleType type = op.getInput().getType();
1667 emitExpression(op.getInput());
1668 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1672void Emitter::emitExpression(SubindexOp op) {
1673 emitExpression(op.getInput());
1680void Emitter::emitExpression(SubaccessOp op) {
1681 emitExpression(op.getInput());
1683 emitExpression(op.getIndex());
1687void Emitter::emitExpression(OpenSubfieldOp op) {
1688 auto type = op.getInput().getType();
1689 emitExpression(op.getInput());
1690 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1694void Emitter::emitExpression(DomainSubfieldOp op) {
1695 emitExpression(op.getInput());
1696 ps <<
"." << legalize(op.getFieldName());
1699void Emitter::emitExpression(OpenSubindexOp op) {
1700 emitExpression(op.getInput());
1706void Emitter::emitExpression(DomainAnyRefCastOp op) {
1707 emitExpression(op.getInput());
1710void Emitter::emitExpression(RefSendOp op) {
1712 emitExpression(op.getBase());
1716void Emitter::emitExpression(RefResolveOp op) {
1718 emitExpression(op.getRef());
1722void Emitter::emitExpression(RefSubOp op) {
1723 emitExpression(op.getInput());
1724 FIRRTLTypeSwitch<FIRRTLBaseType, void>(op.getInput().getType().getType())
1725 .Case<FVectorType>([&](
auto type) {
1731 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1734void Emitter::emitExpression(RWProbeOp op) {
1738 auto target = symInfos->get().irn.lookup(op.getTarget());
1740 if (target.isPort()) {
1741 auto mod = cast<FModuleOp>(target.getOp());
1742 auto port = target.getPort();
1743 base = mod.getArgument(port);
1745 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1748 emitExpression(base);
1751 auto fieldID = target.getField();
1752 auto type = base.getType();
1754 FIRRTLTypeSwitch<Type, void>(type)
1755 .Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1756 auto index = vecTy.getIndexForFieldID(fieldID);
1760 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1762 fieldID = subfieldID;
1764 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1765 auto index = bundleTy.getIndexForFieldID(fieldID);
1766 ps <<
"." << bundleTy.getElementName(index);
1767 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1769 fieldID = subfieldID;
1775void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1777void Emitter::emitExpression(UninferredResetCastOp op) {
1778 emitExpression(op.getInput());
1781void Emitter::emitExpression(FIntegerConstantOp op) {
1782 if (failed(requireVersion(FIRVersion(3, 1, 0), op,
"Integers")))
1789void Emitter::emitExpression(BoolConstantOp op) {
1790 if (failed(requireVersion({6, 0, 0}, op,
"Bools")))
1792 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1795void Emitter::emitExpression(DoubleConstantOp op) {
1796 if (failed(requireVersion({6, 0, 0}, op,
"Doubles")))
1803 SmallString<16> str;
1804 op.getValueAttr().getValue().toString(str);
1809void Emitter::emitExpression(StringConstantOp op) {
1810 if (failed(requireVersion(FIRVersion(3, 1, 0), op,
"Strings")))
1817void Emitter::emitExpression(ListCreateOp op) {
1818 if (failed(requireVersion(FIRVersion(4, 0, 0), op,
"Lists")))
1820 return emitLiteralExpression(op.getType(), op.getElements());
1823void Emitter::emitExpression(UnresolvedPathOp op) {
1824 if (failed(requireVersion({6, 0, 0}, op,
"Paths")))
1831void Emitter::emitExpression(GenericIntrinsicOp op) {
1832 if (failed(requireVersion(FIRVersion(4, 0, 0), op,
"generic intrinsics")))
1834 emitGenericIntrinsic(op);
1837void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1839void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1840 ArrayRef<uint32_t>
attrs) {
1841 ps << mnemonic <<
"(" << PP::ibox0;
1842 interleaveComma(op->getOperands());
1843 if (!op->getOperands().empty() && !
attrs.empty())
1844 ps <<
"," << PP::space;
1846 ps <<
")" << PP::end;
1849void Emitter::emitExpression(CatPrimOp op) {
1850 size_t numOperands = op.getNumOperands();
1851 switch (numOperands) {
1854 emitType(op.getType(),
false);
1858 auto operand = op->getOperand(0);
1860 if (isa<UIntType>(operand.getType()))
1861 return emitExpression(operand);
1864 ps <<
"cat(" << PP::ibox0;
1865 emitExpression(op->getOperand(0));
1866 ps <<
"," << PP::space <<
"SInt<0>(0))" << PP::end;
1872 for (
size_t i = 0; i < numOperands - 1; ++i) {
1873 ps <<
"cat(" << PP::ibox0;
1874 emitExpression(op->getOperand(i));
1875 ps <<
"," << PP::space;
1878 emitExpression(op->getOperand(numOperands - 1));
1879 for (
size_t i = 0; i < numOperands - 1; ++i)
1880 ps <<
")" << PP::end;
1885void Emitter::emitExpression(UnsafeDomainCastOp op) {
1886 if (failed(requireVersion(
nextFIRVersion, op,
"unsafe_domain_cast")))
1888 ps <<
"unsafe_domain_cast(" << PP::ibox0;
1889 interleaveComma(op.getOperands(),
1890 [&](Value operand) { emitExpression(operand); });
1891 ps <<
")" << PP::end;
1894void Emitter::emitExpression(UnknownValueOp op) {
1896 requireVersion(
nextFIRVersion, op,
"unknown property expressions")))
1899 emitType(op.getType());
1903void Emitter::emitAttribute(MemDirAttr attr) {
1905 case MemDirAttr::Infer:
1908 case MemDirAttr::Read:
1911 case MemDirAttr::Write:
1914 case MemDirAttr::ReadWrite:
1920void Emitter::emitAttribute(RUWBehaviorAttr attr) {
1921 switch (attr.getValue()) {
1922 case RUWBehavior::Undefined:
1925 case RUWBehavior::Old:
1928 case RUWBehavior::New:
1935void Emitter::emitType(Type type,
bool includeConst) {
1936 if (includeConst &&
isConst(type))
1938 auto emitWidth = [&](std::optional<int32_t> width) {
1946 FIRRTLTypeSwitch<Type>(type)
1947 .Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1948 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1949 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1950 .Case<UIntType>([&](
auto type) {
1952 emitWidth(type.getWidth());
1954 .Case<SIntType>([&](
auto type) {
1956 emitWidth(type.getWidth());
1958 .Case<AnalogType>([&](
auto type) {
1960 emitWidth(type.getWidth());
1962 .Case<OpenBundleType, BundleType>([&](
auto type) {
1964 if (!type.getElements().empty())
1966 bool anyEmitted =
false;
1968 for (
auto &element : type.getElements()) {
1970 ps <<
"," << PP::space;
1974 ps << legalize(element.name);
1975 emitTypeWithColon(element.type);
1984 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1985 emitType(type.getElementType());
1990 .Case<RefType>([&](RefType type) {
1991 if (type.getForceable())
1994 ps.
cbox(2, IndentStyle::Block);
1996 emitType(type.getType());
1997 if (
auto layer = type.getLayer()) {
2000 emitSymbol(type.getLayer());
2002 ps << BreakToken(0, -2) <<
">";
2005 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
2006 .Case<StringType>([&](StringType type) { ps <<
"String"; })
2007 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
2008 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
2009 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
2010 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
2011 .Case<ListType>([&](ListType type) {
2013 emitType(type.getElementType());
2016 .Case<RegistryType>([&](RegistryType type) {
2018 emitType(type.getElementType());
2021 .Case<DomainType>([&](DomainType type) {
2022 ps <<
"Domain of " << PPExtString(type.getName().getValue());
2024 .Default([&](
auto type) {
2025 llvm_unreachable(
"all types should be implemented");
2029void Emitter::emitDomains(Attribute attr, ArrayRef<PortInfo> ports) {
2032 auto domains = cast<ArrayAttr>(attr);
2033 if (domains.empty())
2037 interleaveComma(domains, [&](Attribute attr) {
2038 ps.
addAsString(ports[cast<IntegerAttr>(attr).getUInt()].name.getValue());
2046void Emitter::emitLocation(Location loc) {
2048 ps << PP::neverbreak;
2050 dyn_cast_or_null<FileLineColLoc, LocationAttr>(LocationAttr(loc))) {
2051 ps <<
" @[" << fileLoc.getFilename().getValue();
2052 if (
auto line = fileLoc.getLine()) {
2055 if (
auto col = fileLoc.getColumn()) {
2072 std::optional<size_t> targetLineLength,
2075 return module.emitError("--firrtl-version ")
2076 << version << " is below the minimum supported "
2077 << "version " << minimumFIRVersion;
2078 Emitter emitter(os, version,
2079 targetLineLength.value_or(defaultTargetLineLength));
2080 for (
auto &op : *module.getBody()) {
2081 if (
auto circuitOp = dyn_cast<CircuitOp>(op))
2082 emitter.emitCircuit(circuitOp);
2084 return emitter.finalize();
2089 "target-line-length",
2090 llvm::cl::desc(
"Target line length for emitted .fir; 0 disables line "
2092 llvm::cl::value_desc(
"number of chars"),
2093 llvm::cl::init(defaultTargetLineLength));
2096 llvm::cl::desc(
"FIRRTL version to target (e.g. \"3.0.0\"). "
2097 "Defaults to the latest supported version."),
2098 llvm::cl::value_desc(
"major.minor.patch"), llvm::cl::init(
""));
2099 static mlir::TranslateFromMLIRRegistration toFIR(
2100 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
2101 [](ModuleOp module, llvm::raw_ostream &os) -> mlir::LogicalResult {
2103 if (!firrtlVersionStr.empty()) {
2106 return module.emitError("invalid --firrtl-version: '")
2108 << "', expected format 'major.minor.patch'";
2111 return exportFIRFile(module, os, targetLineLength, version);
2113 [](mlir::DialectRegistry ®istry) {
2114 registry.insert<chirrtl::CHIRRTLDialect>();
2115 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)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
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.
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="\"")
BaseTy type_cast(Type type)
mlir::LogicalResult exportFIRFile(mlir::ModuleOp module, llvm::raw_ostream &os, std::optional< size_t > targetLineLength, FIRVersion version)
constexpr FIRVersion nextFIRVersion(7, 0, 0)
The next version of FIRRTL that is not yet released.
constexpr FIRVersion exportFIRVersion
The version of FIRRTL that the exporter produces.
void registerToFIRFileTranslation()
bool isConst(Type type)
Returns true if this is a 'const' type whose value is guaranteed to be unchanging at circuit executio...
constexpr FIRVersion missingSpecFIRVersion
A marker for parser features that are currently missing from the spec.
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
constexpr FIRVersion minimumFIRVersion(2, 0, 0)
The current minimum version of FIRRTL that the parser supports.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
The FIRRTL specification version.
static std::optional< FIRVersion > fromString(StringRef str)
Parse a version string of the form "major.minor.patch".