21#include "mlir/IR/BuiltinOps.h"
22#include "mlir/Tools/mlir-translate/Translation.h"
23#include "llvm/ADT/APSInt.h"
24#include "llvm/ADT/StringSet.h"
25#include "llvm/ADT/TypeSwitch.h"
26#include "llvm/Support/Debug.h"
28#define DEBUG_TYPE "export-firrtl"
31using namespace firrtl;
32using namespace chirrtl;
33using namespace pretty;
42constexpr size_t defaultTargetLineLength = 80;
46 Emitter(llvm::raw_ostream &os,
FIRVersion version,
47 size_t targetLineLength = defaultTargetLineLength)
48 : pp(os, targetLineLength), ps(pp, saver), version(version) {
49 pp.setListener(&saver);
51 LogicalResult finalize();
54 void emitCircuit(CircuitOp op);
55 void emitModule(FModuleOp op);
56 void emitModule(FExtModuleOp op);
57 void emitModule(FIntModuleOp op);
58 void emitModulePorts(ArrayRef<PortInfo> ports,
59 Block::BlockArgListType arguments = {});
60 void emitModuleParameters(Operation *op, ArrayAttr parameters);
61 void emitDeclaration(DomainOp op);
62 void emitDeclaration(LayerOp op);
63 void emitDeclaration(OptionOp op);
64 void emitDeclaration(FormalOp op);
65 void emitDeclaration(SimulationOp op);
66 void emitFormalLike(Operation *op, StringRef keyword, StringAttr symName,
67 StringAttr moduleName, DictionaryAttr params);
68 void emitEnabledLayers(ArrayRef<Attribute> layers, Operation *op);
69 void emitKnownLayers(ArrayRef<Attribute> layers, Operation *op);
70 void emitRequirements(ArrayRef<Attribute> requirements);
71 void emitParamAssign(ParamDeclAttr param, Operation *op,
72 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
73 void emitParamValue(Attribute value, Operation *op);
75 void emitGenericIntrinsic(GenericIntrinsicOp op);
78 void emitStatementsInBlock(
Block &block);
79 void emitStatement(WhenOp op);
80 void emitStatement(WireOp op);
81 void emitStatement(RegOp op);
82 void emitStatement(RegResetOp op);
83 void emitStatement(NodeOp op);
84 void emitStatement(StopOp op);
85 void emitStatement(SkipOp op);
86 void emitFormatString(Operation *op, StringRef formatString, OperandRange ops,
87 llvm::SmallVectorImpl<Value> &substitutions);
89 void emitPrintfLike(T op, StringAttr fileName);
90 void emitStatement(PrintFOp op);
91 void emitStatement(FPrintFOp op);
92 void emitStatement(FFlushOp op);
93 void emitStatement(ConnectOp op);
94 void emitStatement(MatchingConnectOp op);
95 void emitStatement(PropertyAssertOp op);
96 void emitStatement(PropAssignOp op);
97 void emitStatement(InstanceOp op);
98 void emitStatement(InstanceChoiceOp op);
99 void emitStatement(AttachOp op);
100 void emitStatement(MemOp op);
101 void emitStatement(InvalidValueOp op);
102 void emitStatement(CombMemOp op);
103 void emitStatement(SeqMemOp op);
104 void emitStatement(MemoryPortOp op);
105 void emitStatement(MemoryDebugPortOp op);
106 void emitStatement(MemoryPortAccessOp op);
107 void emitStatement(DomainDefineOp op);
108 void emitStatement(RefDefineOp op);
109 void emitStatement(RefForceOp op);
110 void emitStatement(RefForceInitialOp op);
111 void emitStatement(RefReleaseOp op);
112 void emitStatement(RefReleaseInitialOp op);
113 void emitStatement(LayerBlockOp op);
114 void emitStatement(GenericIntrinsicOp op);
115 void emitStatement(DomainCreateAnonOp op);
116 void emitStatement(DomainCreateOp op);
119 void emitVerifStatement(T op, StringRef mnemonic);
120 void emitStatement(AssertOp op) { emitVerifStatement(op,
"assert"); }
121 void emitStatement(AssumeOp op) { emitVerifStatement(op,
"assume"); }
122 void emitStatement(CoverOp op) { emitVerifStatement(op,
"cover"); }
125 void emitExpression(Value value);
126 void emitExpression(ConstantOp op);
127 void emitExpression(SpecialConstantOp op);
128 void emitExpression(SubfieldOp op);
129 void emitExpression(SubindexOp op);
130 void emitExpression(SubaccessOp op);
131 void emitExpression(OpenSubfieldOp op);
132 void emitExpression(DomainSubfieldOp op);
133 void emitExpression(OpenSubindexOp op);
134 void emitExpression(RefResolveOp op);
135 void emitExpression(RefSendOp op);
136 void emitExpression(RefSubOp op);
137 void emitExpression(RWProbeOp op);
138 void emitExpression(RefCastOp op);
139 void emitExpression(UninferredResetCastOp op);
140 void emitExpression(ConstCastOp op);
141 void emitExpression(StringConstantOp op);
142 void emitExpression(FIntegerConstantOp op);
143 void emitExpression(BoolConstantOp op);
144 void emitExpression(DoubleConstantOp op);
145 void emitExpression(ListCreateOp op);
146 void emitExpression(UnresolvedPathOp op);
147 void emitExpression(GenericIntrinsicOp op);
148 void emitExpression(CatPrimOp op);
149 void emitExpression(UnsafeDomainCastOp op);
150 void emitExpression(UnknownValueOp op);
152 void emitPrimExpr(StringRef mnemonic, Operation *op,
153 ArrayRef<uint32_t> attrs = {});
155 void emitExpression(BitsPrimOp op) {
156 emitPrimExpr(
"bits", op, {op.getHi(), op.getLo()});
158 void emitExpression(HeadPrimOp op) {
159 emitPrimExpr(
"head", op, op.getAmount());
161 void emitExpression(TailPrimOp op) {
162 emitPrimExpr(
"tail", op, op.getAmount());
164 void emitExpression(PadPrimOp op) { emitPrimExpr(
"pad", op, op.getAmount()); }
165 void emitExpression(ShlPrimOp op) { emitPrimExpr(
"shl", op, op.getAmount()); }
166 void emitExpression(ShrPrimOp op) { emitPrimExpr(
"shr", op, op.getAmount()); }
168 void emitExpression(TimeOp op) {}
171#define HANDLE(OPTYPE, MNEMONIC) \
172 void emitExpression(OPTYPE op) { emitPrimExpr(MNEMONIC, op); }
187 HANDLE(DShlPrimOp,
"dshl");
188 HANDLE(DShlwPrimOp,
"dshlw");
189 HANDLE(DShrPrimOp,
"dshr");
191 HANDLE(AsSIntPrimOp,
"asSInt");
192 HANDLE(AsUIntPrimOp,
"asUInt");
193 HANDLE(AsAsyncResetPrimOp,
"asAsyncReset");
194 HANDLE(AsResetPrimOp,
"asReset");
195 HANDLE(AsClockPrimOp,
"asClock");
199 HANDLE(AndRPrimOp,
"andr");
201 HANDLE(XorRPrimOp,
"xorr");
202 HANDLE(StringConcatOp,
"string_concat");
205 void emitExpression(PropEqOp op) {
206 if (failed(requireVersion({6, 0, 0}, op,
"property equality")))
208 emitPrimExpr(
"prop_eq", op);
211 void emitExpression(BoolAndOp op) {
212 if (failed(requireVersion({6, 0, 0}, op,
"boolean and")))
214 emitPrimExpr(
"bool_and", op);
217 void emitExpression(BoolOrOp op) {
218 if (failed(requireVersion({6, 0, 0}, op,
"boolean or")))
220 emitPrimExpr(
"bool_or", op);
223 void emitExpression(BoolXorOp op) {
224 if (failed(requireVersion({6, 0, 0}, op,
"boolean xor")))
226 emitPrimExpr(
"bool_xor", op);
230 void emitAttribute(MemDirAttr attr);
231 void emitAttribute(RUWBehaviorAttr attr);
234 void emitType(Type type,
bool includeConst =
true);
235 void emitTypeWithColon(Type type) {
236 ps << PP::space <<
":" << PP::nbsp;
241 void emitDomains(Attribute attr, ArrayRef<PortInfo> ports);
244 void emitLocation(Location loc);
245 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
246 template <
typename... Args>
247 void emitLocationAndNewLine(Args... args) {
250 ps << PP::neverbreak;
251 emitLocation(args...);
255 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
256 llvm::function_ref<
void()> emitRHS,
258 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
260 ps.scopedBox(PP::ibox2, [&]() {
262 ps << *wordBeforeLHS << PP::space;
266 ps << PP::space << syntax << PP::nbsp;
268 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
273 void emitSubExprIBox2(Value v) {
274 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
279 template <
typename Container,
typename EachFn>
280 void interleaveComma(
const Container &c, EachFn eachFn) {
281 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
286 void interleaveComma(ValueRange ops) {
287 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
290 void emitStatementFunctionOp(
PPExtString name, Operation *op) {
293 ps.scopedBox(PP::ibox0, [&]() {
294 interleaveComma(op->getOperands());
297 emitLocationAndNewLine(op);
300 template <
typename EachFn,
typename Range>
301 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
304 ps.scopedBox(PP::ibox0, [&]() {
305 interleaveComma(r, eachFn);
310 void emitLiteralExpression(Type type, ValueRange values) {
311 return emitLiteralExpression(type, values,
312 [&](Value v) { emitSubExprIBox2(v); });
316 void emitSymbol(SymbolRefAttr symbol) {
317 ps.ibox(2, IndentStyle::Block);
318 ps << symbol.getRootReference();
319 for (
auto nested : symbol.getNestedReferences()) {
322 ps << nested.getAttr();
329 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
330 encounteredError =
true;
331 return op->emitError(message);
335 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
336 encounteredError =
true;
337 return op->emitOpError(message);
341 LogicalResult requireVersion(
FIRVersion minVersion, Operation *op,
343 if (version >= minVersion)
346 return emitOpError(op, feature +
" requires FIRRTL ") << minVersion;
351 std::optional<StringRef> lookupEmittedName(Value value) {
352 auto it = valueNames.find(value);
353 if (it != valueNames.end())
360 void emitPendingNewlineIfNeeded() {
361 if (pendingNewline) {
362 pendingNewline =
false;
366 void setPendingNewline() {
368 pendingNewline =
true;
371 void startStatement() { emitPendingNewlineIfNeeded(); }
389 bool pendingNewline =
false;
392 bool encounteredError =
false;
397 DenseMap<Value, StringRef> valueNames;
398 StringSet<> valueNamesStorage;
402 StringAttr legalize(StringAttr attr) {
403 StringRef str = attr.getValue();
404 if (str.empty() || !
isdigit(str.front()))
406 return StringAttr::get(attr.getContext(),
"`" + Twine(attr) +
"`");
409 void addValueName(Value value, StringAttr attr) {
410 valueNames.insert({value, attr.getValue()});
412 void addValueName(Value value, StringRef str) {
413 auto it = valueNamesStorage.insert(str);
414 valueNames.insert({value, it.first->getKey()});
416 void addForceable(Forceable op, StringAttr attr) {
417 addValueName(op.getData(), attr);
418 if (op.isForceable()) {
419 SmallString<32> rwName;
420 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
421 addValueName(op.getDataRef(), rwName);
430 SymbolTable symbolTable;
433 SymInfos(Operation *op) : symbolTable(op), istc(op) {}
435 std::optional<std::reference_wrapper<SymInfos>> symInfos;
442LogicalResult Emitter::finalize() {
return failure(encounteredError); }
445void Emitter::emitCircuit(CircuitOp op) {
446 circuitNamespace.add(op);
447 SymInfos circuitSymInfos(op);
448 symInfos = circuitSymInfos;
450 ps <<
"FIRRTL version ";
457 ps <<
"circuit " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
461 if (encounteredError)
463 TypeSwitch<Operation *>(&bodyOp)
464 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](
auto op) {
468 .Case<DomainOp, LayerOp, OptionOp, FormalOp, SimulationOp>(
469 [&](
auto op) { emitDeclaration(op); })
470 .Default([&](
auto op) {
471 emitOpError(op,
"not supported for emission inside circuit");
475 circuitNamespace.clear();
476 symInfos = std::nullopt;
479void Emitter::emitEnabledLayers(ArrayRef<Attribute> layers, Operation *op) {
482 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"enabled layers")))
484 for (
auto layer : layers) {
486 ps.
cbox(2, IndentStyle::Block);
487 ps <<
"enablelayer" << PP::space;
488 emitSymbol(cast<SymbolRefAttr>(layer));
493void Emitter::emitKnownLayers(ArrayRef<Attribute> layers, Operation *op) {
496 if (failed(requireVersion({6, 0, 0}, op,
"known layers")))
498 for (
auto layer : layers) {
500 ps.
cbox(2, IndentStyle::Block);
501 ps <<
"knownlayer" << PP::space;
502 emitSymbol(cast<SymbolRefAttr>(layer));
507void Emitter::emitRequirements(ArrayRef<Attribute> requirements) {
508 if (requirements.empty())
511 ps.
cbox(2, IndentStyle::Block);
512 ps <<
"requires" << PP::space;
513 llvm::interleaveComma(requirements, ps, [&](Attribute req) {
519void Emitter::emitParamAssign(ParamDeclAttr param, Operation *op,
520 std::optional<PPExtString> wordBeforeLHS) {
522 ps << *wordBeforeLHS << PP::nbsp;
524 ps <<
PPExtString(param.getName().strref()) << PP::nbsp <<
"=" << PP::nbsp;
525 emitParamValue(param.getValue(), op);
528void Emitter::emitParamValue(Attribute value, Operation *op) {
529 TypeSwitch<Attribute>(value)
530 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
531 .Case<FloatAttr>([&](
auto attr) {
533 attr.getValue().toString(str);
538 .Case<ArrayAttr>([&](
auto attr) {
541 interleaveComma(attr.getValue(),
542 [&](
auto element) { emitParamValue(element, op); });
546 .Case<DictionaryAttr>([&](
auto attr) {
549 interleaveComma(attr.getValue(), [&](
auto field) {
550 ps << PPExtString(field.getName()) << PP::nbsp <<
"=" << PP::nbsp;
551 emitParamValue(field.getValue(), op);
556 .Default([&](
auto attr) {
557 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
558 ps <<
"<unsupported-attr ";
564void Emitter::emitGenericIntrinsic(GenericIntrinsicOp op) {
568 ps << op.getIntrinsic();
570 auto params = op.getParameters();
571 if (!params.empty()) {
573 ps.scopedBox(PP::ibox0, [&]() {
575 params.getAsRange<ParamDeclAttr>(),
576 [&](ParamDeclAttr param) { emitParamAssign(param, op); });
581 if (op.getNumResults() != 0)
582 emitTypeWithColon(op.getResult().getType());
584 if (op.getNumOperands() != 0) {
585 ps <<
"," << PP::space;
586 ps.
scopedBox(PP::ibox0, [&]() { interleaveComma(op->getOperands()); });
593void Emitter::emitModule(FModuleOp op) {
595 ps.
cbox(4, IndentStyle::Block);
596 if (op.isPublic() &&
FIRVersion(3, 3, 0) <= version)
597 ps <<
"public" << PP::nbsp;
598 ps <<
"module " <<
PPExtString(legalize(op.getNameAttr()));
599 emitEnabledLayers(op.getLayers(), op);
600 ps << PP::nbsp <<
":" << PP::end;
607 auto ports = op.getPorts();
608 emitModulePorts(ports, op.getArguments());
609 if (!ports.empty() && !op.getBodyBlock()->empty())
613 emitStatementsInBlock(*op.getBodyBlock());
616 valueNamesStorage.clear();
620void Emitter::emitModule(FExtModuleOp op) {
622 ps.
cbox(4, IndentStyle::Block);
623 ps <<
"extmodule " <<
PPExtString(legalize(op.getNameAttr()));
624 emitKnownLayers(op.getKnownLayers(), op);
625 emitEnabledLayers(op.getLayers(), op);
626 if (
auto reqs = op.getExternalRequirements())
627 emitRequirements(reqs.getValue());
628 ps << PP::nbsp <<
":" << PP::end;
635 auto ports = op.getPorts();
636 emitModulePorts(ports);
639 if (op.getDefname() && !op.getDefname()->empty()) {
641 ps <<
"defname = " <<
PPExtString(*op.getDefname());
646 emitModuleParameters(op, op.getParameters());
651void Emitter::emitModule(FIntModuleOp op) {
653 emitOpError(op,
"intrinsic modules were removed in FIRRTL 4.0.0");
657 ps.
cbox(4, IndentStyle::Block);
658 ps <<
"intmodule " <<
PPExtString(legalize(op.getNameAttr()));
659 emitEnabledLayers(op.getLayers(), op);
660 ps << PP::nbsp <<
":" << PP::end;
667 auto ports = op.getPorts();
668 emitModulePorts(ports);
671 ps <<
"intrinsic = " <<
PPExtString(op.getIntrinsic());
675 emitModuleParameters(op, op.getParameters());
682void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
683 Block::BlockArgListType arguments) {
685 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
687 const auto &port = ports[i];
688 ps << (port.direction == Direction::In ?
"input " :
"output ");
689 auto legalName = legalize(port.name);
690 if (!arguments.empty())
691 addValueName(arguments[i], legalName);
694 emitDomains(port.domains, ports);
695 emitLocation(ports[i].loc);
700void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
701 for (
auto param : parameters.getAsRange<ParamDeclAttr>()) {
703 emitParamAssign(param, op,
PPExtString(
"parameter"));
708void Emitter::emitDeclaration(DomainOp op) {
712 ps <<
"domain " <<
PPExtString(op.getSymName()) <<
" :";
713 emitLocationAndNewLine(op);
715 for (
auto attr : op.getFields()) {
716 auto fieldAttr = cast<DomainFieldAttr>(attr);
717 ps << PP::newline <<
PPExtString(fieldAttr.getName()) <<
" : ";
718 emitType(fieldAttr.getType());
724void Emitter::emitDeclaration(LayerOp op) {
725 if (failed(requireVersion(
FIRVersion(3, 3, 0), op,
"layers")))
727 if (op.getConvention() == LayerConvention::Inline &&
728 failed(requireVersion(
FIRVersion(4, 1, 0), op,
"inline layers")))
731 ps <<
"layer " <<
PPExtString(op.getSymName()) <<
", "
732 <<
PPExtString(stringifyLayerConvention(op.getConvention()));
734 if (
auto outputFile = op->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
740 emitLocationAndNewLine(op);
742 for (
auto &bodyOp : op.getBody().getOps()) {
743 TypeSwitch<Operation *>(&bodyOp)
744 .Case<LayerOp>([&](
auto op) { emitDeclaration(op); })
745 .Default([&](
auto op) {
747 "not supported for emission inside layer definition");
754void Emitter::emitDeclaration(OptionOp op) {
758 ps <<
"option " <<
PPExtString(legalize(op.getSymNameAttr())) <<
" :";
761 for (
auto caseOp : op.getBody().getOps<OptionCaseOp>()) {
763 ps <<
PPExtString(legalize(caseOp.getSymNameAttr()));
764 emitLocation(caseOp);
767 ps << PP::newline << PP::newline;
771void Emitter::emitDeclaration(FormalOp op) {
772 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"formal tests")))
774 emitFormalLike(op,
"formal", op.getSymNameAttr(),
775 op.getModuleNameAttr().getAttr(), op.getParameters());
779void Emitter::emitDeclaration(SimulationOp op) {
780 if (failed(requireVersion(
nextFIRVersion, op,
"simulation tests")))
782 emitFormalLike(op,
"simulation", op.getSymNameAttr(),
783 op.getModuleNameAttr().getAttr(), op.getParameters());
787void Emitter::emitFormalLike(Operation *op, StringRef keyword,
788 StringAttr symName, StringAttr moduleName,
789 DictionaryAttr params) {
791 ps.
cbox(4, IndentStyle::Block);
792 ps << keyword <<
" " <<
PPExtString(legalize(symName));
794 ps << PP::nbsp <<
":" << PP::end;
799 for (
auto param : params) {
801 ps <<
PPExtString(param.getName()) << PP::nbsp <<
"=" << PP::nbsp;
802 emitParamValue(param.getValue(), op);
816 return (
isExpression(op) && !isa<InvalidValueOp>(op)) ||
817 (isa<GenericIntrinsicOp>(op) && op->hasOneUse() &&
821void Emitter::emitStatementsInBlock(Block &block) {
822 for (
auto &bodyOp : block) {
823 if (encounteredError)
827 TypeSwitch<Operation *>(&bodyOp)
828 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
829 PrintFOp, FPrintFOp, FFlushOp, AssertOp, AssumeOp, CoverOp,
830 ConnectOp, MatchingConnectOp, PropertyAssertOp, PropAssignOp,
831 InstanceOp, InstanceChoiceOp, AttachOp, MemOp, InvalidValueOp,
832 SeqMemOp, CombMemOp, MemoryPortOp, MemoryDebugPortOp,
833 MemoryPortAccessOp, DomainDefineOp, RefDefineOp, RefForceOp,
834 RefForceInitialOp, RefReleaseOp, RefReleaseInitialOp,
835 LayerBlockOp, GenericIntrinsicOp, DomainCreateAnonOp,
836 DomainCreateOp>([&](
auto op) { emitStatement(op); })
837 .Default([&](
auto op) {
839 ps <<
"// operation " <<
PPExtString(op->getName().getStringRef());
841 emitOpError(op,
"not supported as statement");
846void Emitter::emitStatement(WhenOp op) {
849 emitExpression(op.getCondition());
851 emitLocationAndNewLine(op);
852 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
854 if (!op.hasElseRegion())
861 auto &elseBlock = op.getElseBlock();
862 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
863 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
864 emitStatement(whenOp);
871 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
874void Emitter::emitStatement(WireOp op) {
875 auto legalName = legalize(op.getNameAttr());
876 addForceable(op, legalName);
880 emitTypeWithColon(op.getResult().getType());
883 if (!op.getDomains().empty()) {
884 ps << PP::space <<
"domains" << PP::space <<
"[";
886 llvm::interleaveComma(op.getDomains(), ps, [&](Value domain) {
887 auto name = lookupEmittedName(domain);
888 assert(name &&
"domain value must have a name");
889 ps << PPExtString(*name);
895 emitLocationAndNewLine(op);
898void Emitter::emitStatement(RegOp op) {
899 auto legalName = legalize(op.getNameAttr());
900 addForceable(op, legalName);
904 emitTypeWithColon(op.getResult().getType());
905 ps <<
"," << PP::space;
906 emitExpression(op.getClockVal());
908 emitLocationAndNewLine(op);
911void Emitter::emitStatement(RegResetOp op) {
912 auto legalName = legalize(op.getNameAttr());
913 addForceable(op, legalName);
917 ps <<
"regreset " << legalName;
918 emitTypeWithColon(op.getResult().getType());
919 ps <<
"," << PP::space;
920 emitExpression(op.getClockVal());
921 ps <<
"," << PP::space;
922 emitExpression(op.getResetSignal());
923 ps <<
"," << PP::space;
924 emitExpression(op.getResetValue());
928 ps <<
"reg " << legalName;
929 emitTypeWithColon(op.getResult().getType());
930 ps <<
"," << PP::space;
931 emitExpression(op.getClockVal());
932 ps << PP::space <<
"with :";
934 ps << PP::neverbreak;
937 ps <<
"reset => (" << PP::ibox0;
938 emitExpression(op.getResetSignal());
939 ps <<
"," << PP::space;
940 emitExpression(op.getResetValue());
941 ps <<
")" << PP::end;
944 emitLocationAndNewLine(op);
947void Emitter::emitStatement(NodeOp op) {
948 auto legalName = legalize(op.getNameAttr());
949 addForceable(op, legalName);
951 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(legalName); },
952 [&]() { emitExpression(op.getInput()); });
953 emitLocationAndNewLine(op);
956void Emitter::emitStatement(StopOp op) {
959 ps <<
"stop(" << PP::ibox0;
960 emitExpression(op.getClock());
961 ps <<
"," << PP::space;
962 emitExpression(op.getCond());
963 ps <<
"," << PP::space;
965 ps <<
")" << PP::end;
966 if (!op.getName().empty()) {
967 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
970 emitLocationAndNewLine(op);
973void Emitter::emitStatement(SkipOp op) {
976 emitLocationAndNewLine(op);
979void Emitter::emitFormatString(Operation *op, StringRef origFormatString,
980 OperandRange substitutionOperands,
981 llvm::SmallVectorImpl<Value> &substitutions) {
990 SmallString<64> formatString;
991 for (
size_t i = 0, e = origFormatString.size(), opIdx = 0; i != e; ++i) {
992 auto c = origFormatString[i];
995 formatString.push_back(c);
998 SmallString<6> width;
999 c = origFormatString[++i];
1002 c = origFormatString[++i];
1011 formatString.append(width);
1014 substitutions.push_back(substitutionOperands[opIdx++]);
1017 formatString.push_back(c);
1022 if (origFormatString.slice(i, i + 4) ==
"{{}}") {
1023 formatString.append(
"{{");
1024 TypeSwitch<Operation *>(substitutionOperands[opIdx++].getDefiningOp())
1026 [&](
auto time) { formatString.append(
"SimulationTime"); })
1027 .Case<HierarchicalModuleNameOp>([&](
auto time) {
1028 formatString.append(
"HierarchicalModuleName");
1030 .Default([&](
auto) {
1031 emitError(op,
"unsupported fstring substitution type");
1033 formatString.append(
"}}");
1038 formatString.push_back(c);
1044void Emitter::emitStatement(PrintFOp op) {
1047 ps <<
"printf(" << PP::ibox0;
1048 emitExpression(op.getClock());
1049 ps <<
"," << PP::space;
1050 emitExpression(op.getCond());
1051 ps <<
"," << PP::space;
1053 SmallVector<Value, 4> substitutions;
1054 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
1056 for (
auto operand : substitutions) {
1057 ps <<
"," << PP::space;
1058 emitExpression(operand);
1060 ps <<
")" << PP::end;
1061 if (!op.getName().empty()) {
1062 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1065 emitLocationAndNewLine(op);
1068void Emitter::emitStatement(FPrintFOp op) {
1069 if (failed(requireVersion({6, 0, 0}, op,
"fprintf")))
1073 ps <<
"fprintf(" << PP::ibox0;
1074 emitExpression(op.getClock());
1075 ps <<
"," << PP::space;
1076 emitExpression(op.getCond());
1077 ps <<
"," << PP::space;
1079 SmallVector<Value, 4> outputFileSubstitutions;
1080 emitFormatString(op, op.getOutputFile(), op.getOutputFileSubstitutions(),
1081 outputFileSubstitutions);
1082 if (!outputFileSubstitutions.empty()) {
1083 ps <<
"," << PP::space;
1084 interleaveComma(outputFileSubstitutions);
1087 ps <<
"," << PP::space;
1088 SmallVector<Value, 4> substitutions;
1089 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
1091 if (!substitutions.empty()) {
1092 ps <<
"," << PP::space;
1093 interleaveComma(substitutions);
1096 ps <<
")" << PP::end;
1097 if (!op.getName().empty()) {
1098 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1101 emitLocationAndNewLine(op);
1104void Emitter::emitStatement(FFlushOp op) {
1105 if (failed(requireVersion({6, 0, 0}, op,
"fflush")))
1109 ps <<
"fflush(" << PP::ibox0;
1110 emitExpression(op.getClock());
1111 ps <<
"," << PP::space;
1112 emitExpression(op.getCond());
1113 if (op.getOutputFileAttr()) {
1114 ps <<
"," << PP::space;
1115 SmallVector<Value, 4> substitutions;
1116 emitFormatString(op, op.getOutputFileAttr(),
1117 op.getOutputFileSubstitutions(), substitutions);
1118 if (!substitutions.empty()) {
1119 ps <<
"," << PP::space;
1120 interleaveComma(substitutions);
1123 ps <<
")" << PP::end;
1125 emitLocationAndNewLine(op);
1129void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
1132 ps << mnemonic <<
"(" << PP::ibox0;
1133 emitExpression(op.getClock());
1134 ps <<
"," << PP::space;
1135 emitExpression(op.getPredicate());
1136 ps <<
"," << PP::space;
1137 emitExpression(op.getEnable());
1138 ps <<
"," << PP::space;
1140 ps <<
")" << PP::end;
1141 if (!op.getName().empty()) {
1142 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1145 emitLocationAndNewLine(op);
1148void Emitter::emitStatement(ConnectOp op) {
1152 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1153 ps <<
"invalidate" << PP::space;
1154 emitExpression(op.getDest());
1156 ps <<
"connect" << PP::space;
1157 emitExpression(op.getDest());
1158 ps <<
"," << PP::space;
1159 emitExpression(op.getSrc());
1163 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1164 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1166 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1169 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1172 emitLocationAndNewLine(op);
1175void Emitter::emitStatement(MatchingConnectOp op) {
1179 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1180 ps <<
"invalidate" << PP::space;
1181 emitExpression(op.getDest());
1183 ps <<
"connect" << PP::space;
1184 emitExpression(op.getDest());
1185 ps <<
"," << PP::space;
1186 emitExpression(op.getSrc());
1190 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1191 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1193 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1196 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1199 emitLocationAndNewLine(op);
1202void Emitter::emitStatement(PropertyAssertOp op) {
1203 if (failed(requireVersion(
FIRVersion(6, 0, 0), op,
"property assert")))
1207 ps <<
"propassert" << PP::space;
1208 emitExpression(op.getCondition());
1209 ps <<
"," << PP::space;
1214 auto expr = dyn_cast<StringConstantOp>(op.getMessage().getDefiningOp());
1217 emitOpError(op,
"unable to emit non-literal string expressions "
1218 "when targeting FIRRTL version <= 7.0.0");
1219 diag.attachNote(op.getMessage().getLoc())
1220 <<
"non-literal expression is here";
1223 emitExpression(op.getMessage());
1226 emitLocationAndNewLine(op);
1229void Emitter::emitStatement(PropAssignOp op) {
1230 if (failed(requireVersion(
FIRVersion(3, 1, 0), op,
"properties")))
1234 ps <<
"propassign" << PP::space;
1235 interleaveComma(op.getOperands());
1237 emitLocationAndNewLine(op);
1240void Emitter::emitStatement(InstanceOp op) {
1242 auto legalName = legalize(op.getNameAttr());
1244 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
1245 emitLocationAndNewLine(op);
1249 SmallString<16> portName(legalName);
1250 portName.push_back(
'.');
1251 unsigned baseLen = portName.size();
1252 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1253 portName.append(legalize(op.getPortNameAttr(i)));
1254 addValueName(op.getResult(i), portName);
1255 portName.resize(baseLen);
1259void Emitter::emitStatement(InstanceChoiceOp op) {
1261 "option groups/instance choices")))
1264 auto legalName = legalize(op.getNameAttr());
1265 ps <<
"instchoice " <<
PPExtString(legalName) <<
" of "
1266 <<
PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
1267 <<
PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
1270 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
1272 ps <<
PPExtString(legalize(optSym.getLeafReference()));
1277 setPendingNewline();
1279 SmallString<16> portName(legalName);
1280 portName.push_back(
'.');
1281 unsigned baseLen = portName.size();
1282 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1283 portName.append(legalize(op.getPortNameAttr(i)));
1284 addValueName(op.getResult(i), portName);
1285 portName.resize(baseLen);
1289void Emitter::emitStatement(AttachOp op) {
1290 emitStatementFunctionOp(
PPExtString(
"attach"), op);
1293void Emitter::emitStatement(MemOp op) {
1294 auto legalName = legalize(op.getNameAttr());
1295 SmallString<16> portName(legalName);
1296 portName.push_back(
'.');
1297 auto portNameBaseLen = portName.size();
1298 for (
auto result :
llvm::zip(op.getResults(), op.getPortNames())) {
1299 portName.resize(portNameBaseLen);
1300 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
1301 addValueName(std::get<0>(result), portName);
1306 emitLocationAndNewLine(op);
1309 ps <<
"data-type => ";
1310 emitType(op.getDataType());
1315 ps <<
"read-latency => ";
1318 ps <<
"write-latency => ";
1322 SmallString<16> reader, writer, readwriter;
1323 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
1324 auto add = [&](SmallString<16> &to, StringAttr name) {
1327 to.append(name.getValue());
1329 switch (port.second) {
1330 case MemOp::PortKind::Read:
1331 add(reader, legalize(port.first));
1333 case MemOp::PortKind::Write:
1334 add(writer, legalize(port.first));
1336 case MemOp::PortKind::ReadWrite:
1337 add(readwriter, legalize(port.first));
1339 case MemOp::PortKind::Debug:
1340 emitOpError(op,
"has unsupported 'debug' port");
1344 if (!reader.empty())
1345 ps <<
"reader => " << reader << PP::newline;
1346 if (!writer.empty())
1347 ps <<
"writer => " << writer << PP::newline;
1348 if (!readwriter.empty())
1349 ps <<
"readwriter => " << readwriter << PP::newline;
1351 ps <<
"read-under-write => ";
1352 emitAttribute(op.getRuwAttr());
1353 setPendingNewline();
1357void Emitter::emitStatement(SeqMemOp op) {
1360 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
1361 emitTypeWithColon(op.getType());
1362 ps <<
"," << PP::space;
1363 emitAttribute(op.getRuwAttr());
1365 emitLocationAndNewLine(op);
1368void Emitter::emitStatement(CombMemOp op) {
1371 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
1372 emitTypeWithColon(op.getType());
1374 emitLocationAndNewLine(op);
1377void Emitter::emitStatement(MemoryPortOp op) {
1379 addValueName(op.getData(), legalize(op.getNameAttr()));
1382void Emitter::emitStatement(MemoryDebugPortOp op) {
1384 addValueName(op.getData(), legalize(op.getNameAttr()));
1387void Emitter::emitStatement(MemoryPortAccessOp op) {
1391 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1392 emitAttribute(port.getDirection());
1394 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
1397 auto *mem = port.getMemory().getDefiningOp();
1398 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1399 ps << legalize(seqMem.getNameAttr());
1401 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1405 emitExpression(op.getIndex());
1409 emitExpression(op.getClock());
1411 emitLocationAndNewLine(op);
1414void Emitter::emitStatement(DomainDefineOp op) {
1418 if (isa_and_nonnull<DomainCreateAnonOp>(op.getSrc().getDefiningOp()))
1422 emitAssignLike([&]() { emitExpression(op.getDest()); },
1423 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1425 emitLocationAndNewLine(op);
1428void Emitter::emitStatement(RefDefineOp op) {
1430 emitAssignLike([&]() { emitExpression(op.getDest()); },
1431 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1433 emitLocationAndNewLine(op);
1436void Emitter::emitStatement(RefForceOp op) {
1437 emitStatementFunctionOp(
PPExtString(
"force"), op);
1440void Emitter::emitStatement(RefForceInitialOp op) {
1442 auto constantPredicate =
1443 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1444 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1447 emitExpression(op.getPredicate());
1448 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1450 ps <<
"force_initial(";
1452 interleaveComma({op.getDest(), op.getSrc()});
1457 emitLocationAndNewLine(op);
1460void Emitter::emitStatement(RefReleaseOp op) {
1461 emitStatementFunctionOp(
PPExtString(
"release"), op);
1464void Emitter::emitStatement(RefReleaseInitialOp op) {
1466 auto constantPredicate =
1467 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1468 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1471 emitExpression(op.getPredicate());
1472 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1474 ps <<
"release_initial(";
1475 emitExpression(op.getDest());
1479 emitLocationAndNewLine(op);
1482void Emitter::emitStatement(LayerBlockOp op) {
1483 if (failed(requireVersion(
FIRVersion(3, 3, 0), op,
"layers")))
1486 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1487 emitLocationAndNewLine(op);
1488 auto *body = op.getBody();
1489 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1492void Emitter::emitStatement(InvalidValueOp op) {
1495 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1496 return use.getOperandNumber() == 1 &&
1497 isa<ConnectOp, MatchingConnectOp>(use.getOwner());
1503 auto name = circuitNamespace.newName(
"_invalid");
1504 addValueName(op, name);
1506 emitType(op.getType());
1507 emitLocationAndNewLine(op);
1513 emitLocationAndNewLine(op);
1516void Emitter::emitStatement(GenericIntrinsicOp op) {
1517 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"generic intrinsics")))
1521 emitGenericIntrinsic(op);
1524 auto name = circuitNamespace.newName(
"_gen_int");
1525 addValueName(op.getResult(), name);
1526 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(name); },
1527 [&]() { emitGenericIntrinsic(op); });
1529 emitLocationAndNewLine(op);
1532void Emitter::emitStatement(DomainCreateAnonOp op) {
1536void Emitter::emitStatement(DomainCreateOp op) {
1540 auto name = legalize(op.getNameAttr());
1541 addValueName(op.getResult(), name);
1546 auto fieldValues = op.getFieldValues();
1547 if (fieldValues.empty())
1550 ps <<
"(" << PP::ibox0;
1551 interleaveComma(fieldValues, [&](
auto value) { emitExpression(value); });
1552 ps <<
")" << PP::end;
1555 emitLocationAndNewLine(op);
1558void Emitter::emitExpression(Value value) {
1561 if (
auto name = lookupEmittedName(value)) {
1567 auto op = value.getDefiningOp();
1568 assert(op &&
"value must either be a block arg or the result of an op");
1569 TypeSwitch<Operation *>(op)
1572 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1573 OpenSubfieldOp, OpenSubindexOp, DomainSubfieldOp,
1575 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1576 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1577 EQPrimOp, NEQPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1579 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsResetPrimOp,
1580 AsClockPrimOp, CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp,
1583 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1584 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1585 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1586 UnresolvedPathOp, GenericIntrinsicOp, CatPrimOp, UnsafeDomainCastOp,
1587 UnknownValueOp, StringConcatOp, PropEqOp, BoolAndOp, BoolOrOp,
1590 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp,
1592 TimeOp>([&](
auto op) {
1593 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1595 .Default([&](
auto op) {
1596 emitOpError(op,
"not supported as expression");
1597 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1602void Emitter::emitExpression(ConstantOp op) {
1604 emitType(op.getType(),
false);
1611void Emitter::emitExpression(SpecialConstantOp op) {
1612 auto emitInner = [&]() {
1619 .
Case<ClockType>([&](
auto type) {
1624 .Case<ResetType>([&](
auto type) { emitInner(); })
1625 .Case<AsyncResetType>([&](
auto type) {
1626 ps <<
"asAsyncReset(";
1633void Emitter::emitExpression(SubfieldOp op) {
1634 BundleType type = op.getInput().getType();
1635 emitExpression(op.getInput());
1636 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1640void Emitter::emitExpression(SubindexOp op) {
1641 emitExpression(op.getInput());
1648void Emitter::emitExpression(SubaccessOp op) {
1649 emitExpression(op.getInput());
1651 emitExpression(op.getIndex());
1655void Emitter::emitExpression(OpenSubfieldOp op) {
1656 auto type = op.getInput().getType();
1657 emitExpression(op.getInput());
1658 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1662void Emitter::emitExpression(DomainSubfieldOp op) {
1663 emitExpression(op.getInput());
1664 ps <<
"." << legalize(op.getFieldName());
1667void Emitter::emitExpression(OpenSubindexOp op) {
1668 emitExpression(op.getInput());
1674void Emitter::emitExpression(RefSendOp op) {
1676 emitExpression(op.getBase());
1680void Emitter::emitExpression(RefResolveOp op) {
1682 emitExpression(op.getRef());
1686void Emitter::emitExpression(RefSubOp op) {
1687 emitExpression(op.getInput());
1689 .
Case<FVectorType>([&](
auto type) {
1695 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1698void Emitter::emitExpression(RWProbeOp op) {
1702 auto target = symInfos->get().irn.lookup(op.getTarget());
1704 if (target.isPort()) {
1705 auto mod = cast<FModuleOp>(target.getOp());
1706 auto port = target.getPort();
1707 base = mod.getArgument(port);
1709 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1712 emitExpression(base);
1715 auto fieldID = target.getField();
1716 auto type = base.getType();
1719 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1720 auto index = vecTy.getIndexForFieldID(fieldID);
1724 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1726 fieldID = subfieldID;
1728 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1729 auto index = bundleTy.getIndexForFieldID(fieldID);
1730 ps <<
"." << bundleTy.getElementName(index);
1731 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1733 fieldID = subfieldID;
1739void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1741void Emitter::emitExpression(UninferredResetCastOp op) {
1742 emitExpression(op.getInput());
1745void Emitter::emitExpression(FIntegerConstantOp op) {
1746 if (failed(requireVersion(
FIRVersion(3, 1, 0), op,
"Integers")))
1753void Emitter::emitExpression(BoolConstantOp op) {
1754 if (failed(requireVersion({6, 0, 0}, op,
"Bools")))
1756 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1759void Emitter::emitExpression(DoubleConstantOp op) {
1760 if (failed(requireVersion({6, 0, 0}, op,
"Doubles")))
1767 SmallString<16> str;
1768 op.getValueAttr().getValue().toString(str);
1773void Emitter::emitExpression(StringConstantOp op) {
1774 if (failed(requireVersion(
FIRVersion(3, 1, 0), op,
"Strings")))
1781void Emitter::emitExpression(ListCreateOp op) {
1782 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"Lists")))
1784 return emitLiteralExpression(op.getType(), op.getElements());
1787void Emitter::emitExpression(UnresolvedPathOp op) {
1788 if (failed(requireVersion({6, 0, 0}, op,
"Paths")))
1795void Emitter::emitExpression(GenericIntrinsicOp op) {
1796 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"generic intrinsics")))
1798 emitGenericIntrinsic(op);
1801void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1803void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1804 ArrayRef<uint32_t> attrs) {
1805 ps << mnemonic <<
"(" << PP::ibox0;
1806 interleaveComma(op->getOperands());
1807 if (!op->getOperands().empty() && !attrs.empty())
1808 ps <<
"," << PP::space;
1809 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1810 ps <<
")" << PP::end;
1813void Emitter::emitExpression(CatPrimOp op) {
1814 size_t numOperands = op.getNumOperands();
1815 switch (numOperands) {
1818 emitType(op.getType(),
false);
1822 auto operand = op->getOperand(0);
1824 if (isa<UIntType>(operand.getType()))
1825 return emitExpression(operand);
1828 ps <<
"cat(" << PP::ibox0;
1829 emitExpression(op->getOperand(0));
1830 ps <<
"," << PP::space <<
"SInt<0>(0))" << PP::end;
1836 for (
size_t i = 0; i < numOperands - 1; ++i) {
1837 ps <<
"cat(" << PP::ibox0;
1838 emitExpression(op->getOperand(i));
1839 ps <<
"," << PP::space;
1842 emitExpression(op->getOperand(numOperands - 1));
1843 for (
size_t i = 0; i < numOperands - 1; ++i)
1844 ps <<
")" << PP::end;
1849void Emitter::emitExpression(UnsafeDomainCastOp op) {
1850 if (failed(requireVersion(
nextFIRVersion, op,
"unsafe_domain_cast")))
1852 ps <<
"unsafe_domain_cast(" << PP::ibox0;
1853 interleaveComma(op.getOperands(),
1854 [&](Value operand) { emitExpression(operand); });
1855 ps <<
")" << PP::end;
1858void Emitter::emitExpression(UnknownValueOp op) {
1860 requireVersion(
nextFIRVersion, op,
"unknown property expressions")))
1863 emitType(op.getType());
1867void Emitter::emitAttribute(MemDirAttr attr) {
1869 case MemDirAttr::Infer:
1872 case MemDirAttr::Read:
1875 case MemDirAttr::Write:
1878 case MemDirAttr::ReadWrite:
1884void Emitter::emitAttribute(RUWBehaviorAttr attr) {
1885 switch (attr.getValue()) {
1886 case RUWBehavior::Undefined:
1889 case RUWBehavior::Old:
1892 case RUWBehavior::New:
1899void Emitter::emitType(Type type,
bool includeConst) {
1900 if (includeConst &&
isConst(type))
1902 auto emitWidth = [&](std::optional<int32_t> width) {
1911 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1912 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1913 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1914 .Case<UIntType>([&](
auto type) {
1916 emitWidth(type.getWidth());
1918 .Case<SIntType>([&](
auto type) {
1920 emitWidth(type.getWidth());
1922 .Case<AnalogType>([&](
auto type) {
1924 emitWidth(type.getWidth());
1926 .Case<OpenBundleType, BundleType>([&](
auto type) {
1928 if (!type.getElements().empty())
1930 bool anyEmitted =
false;
1932 for (
auto &element : type.getElements()) {
1934 ps <<
"," << PP::space;
1938 ps << legalize(element.name);
1939 emitTypeWithColon(element.type);
1948 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1949 emitType(type.getElementType());
1954 .Case<RefType>([&](RefType type) {
1955 if (type.getForceable())
1958 ps.
cbox(2, IndentStyle::Block);
1960 emitType(type.getType());
1961 if (
auto layer = type.getLayer()) {
1964 emitSymbol(type.getLayer());
1969 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1970 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1971 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1972 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1973 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1974 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1975 .Case<ListType>([&](ListType type) {
1977 emitType(type.getElementType());
1980 .Case<DomainType>([&](DomainType type) {
1981 ps <<
"Domain of " <<
PPExtString(type.getName().getValue());
1983 .Default([&](
auto type) {
1984 llvm_unreachable(
"all types should be implemented");
1988void Emitter::emitDomains(Attribute attr, ArrayRef<PortInfo> ports) {
1991 auto domains = cast<ArrayAttr>(attr);
1992 if (domains.empty())
1996 interleaveComma(domains, [&](Attribute attr) {
1997 ps.
addAsString(ports[cast<IntegerAttr>(attr).getUInt()].name.getValue());
2005void Emitter::emitLocation(Location loc) {
2007 ps << PP::neverbreak;
2009 dyn_cast_or_null<FileLineColLoc, LocationAttr>(LocationAttr(loc))) {
2010 ps <<
" @[" << fileLoc.getFilename().getValue();
2011 if (
auto line = fileLoc.getLine()) {
2014 if (
auto col = fileLoc.getColumn()) {
2031 std::optional<size_t> targetLineLength,
2034 return module.emitError("--firrtl-version ")
2035 << version << " is below the minimum supported "
2036 << "version " << minimumFIRVersion;
2037 Emitter emitter(os, version,
2038 targetLineLength.value_or(defaultTargetLineLength));
2039 for (
auto &op : *
module.getBody()) {
2040 if (auto circuitOp = dyn_cast<CircuitOp>(op))
2041 emitter.emitCircuit(circuitOp);
2043 return emitter.finalize();
2048 "target-line-length",
2049 llvm::cl::desc(
"Target line length for emitted .fir; 0 disables line "
2051 llvm::cl::value_desc(
"number of chars"),
2052 llvm::cl::init(defaultTargetLineLength));
2055 llvm::cl::desc(
"FIRRTL version to target (e.g. \"3.0.0\"). "
2056 "Defaults to the latest supported version."),
2057 llvm::cl::value_desc(
"major.minor.patch"), llvm::cl::init(
""));
2058 static mlir::TranslateFromMLIRRegistration toFIR(
2059 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
2060 [](ModuleOp module, llvm::raw_ostream &os) -> mlir::LogicalResult {
2062 if (!firrtlVersionStr.empty()) {
2063 auto ver = FIRVersion::fromString(firrtlVersionStr);
2065 return module.emitError(
"invalid --firrtl-version: '")
2067 <<
"', expected format 'major.minor.patch'";
2070 return exportFIRFile(module, os, targetLineLength, version);
2072 [](mlir::DialectRegistry ®istry) {
2073 registry.insert<chirrtl::CHIRRTLDialect>();
2074 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 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 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.