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) {
1205 ps <<
"propassert" << PP::space;
1206 emitExpression(op.getCondition());
1207 ps <<
"," << PP::space;
1210 emitLocationAndNewLine(op);
1213void Emitter::emitStatement(PropAssignOp op) {
1214 if (failed(requireVersion(
FIRVersion(3, 1, 0), op,
"properties")))
1218 ps <<
"propassign" << PP::space;
1219 interleaveComma(op.getOperands());
1221 emitLocationAndNewLine(op);
1224void Emitter::emitStatement(InstanceOp op) {
1226 auto legalName = legalize(op.getNameAttr());
1228 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
1229 emitLocationAndNewLine(op);
1233 SmallString<16> portName(legalName);
1234 portName.push_back(
'.');
1235 unsigned baseLen = portName.size();
1236 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1237 portName.append(legalize(op.getPortNameAttr(i)));
1238 addValueName(op.getResult(i), portName);
1239 portName.resize(baseLen);
1243void Emitter::emitStatement(InstanceChoiceOp op) {
1245 "option groups/instance choices")))
1248 auto legalName = legalize(op.getNameAttr());
1249 ps <<
"instchoice " <<
PPExtString(legalName) <<
" of "
1250 <<
PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
1251 <<
PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
1254 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
1256 ps <<
PPExtString(legalize(optSym.getLeafReference()));
1261 setPendingNewline();
1263 SmallString<16> portName(legalName);
1264 portName.push_back(
'.');
1265 unsigned baseLen = portName.size();
1266 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1267 portName.append(legalize(op.getPortNameAttr(i)));
1268 addValueName(op.getResult(i), portName);
1269 portName.resize(baseLen);
1273void Emitter::emitStatement(AttachOp op) {
1274 emitStatementFunctionOp(
PPExtString(
"attach"), op);
1277void Emitter::emitStatement(MemOp op) {
1278 auto legalName = legalize(op.getNameAttr());
1279 SmallString<16> portName(legalName);
1280 portName.push_back(
'.');
1281 auto portNameBaseLen = portName.size();
1282 for (
auto result :
llvm::zip(op.getResults(), op.getPortNames())) {
1283 portName.resize(portNameBaseLen);
1284 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
1285 addValueName(std::get<0>(result), portName);
1290 emitLocationAndNewLine(op);
1293 ps <<
"data-type => ";
1294 emitType(op.getDataType());
1299 ps <<
"read-latency => ";
1302 ps <<
"write-latency => ";
1306 SmallString<16> reader, writer, readwriter;
1307 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
1308 auto add = [&](SmallString<16> &to, StringAttr name) {
1311 to.append(name.getValue());
1313 switch (port.second) {
1314 case MemOp::PortKind::Read:
1315 add(reader, legalize(port.first));
1317 case MemOp::PortKind::Write:
1318 add(writer, legalize(port.first));
1320 case MemOp::PortKind::ReadWrite:
1321 add(readwriter, legalize(port.first));
1323 case MemOp::PortKind::Debug:
1324 emitOpError(op,
"has unsupported 'debug' port");
1328 if (!reader.empty())
1329 ps <<
"reader => " << reader << PP::newline;
1330 if (!writer.empty())
1331 ps <<
"writer => " << writer << PP::newline;
1332 if (!readwriter.empty())
1333 ps <<
"readwriter => " << readwriter << PP::newline;
1335 ps <<
"read-under-write => ";
1336 emitAttribute(op.getRuwAttr());
1337 setPendingNewline();
1341void Emitter::emitStatement(SeqMemOp op) {
1344 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
1345 emitTypeWithColon(op.getType());
1346 ps <<
"," << PP::space;
1347 emitAttribute(op.getRuwAttr());
1349 emitLocationAndNewLine(op);
1352void Emitter::emitStatement(CombMemOp op) {
1355 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
1356 emitTypeWithColon(op.getType());
1358 emitLocationAndNewLine(op);
1361void Emitter::emitStatement(MemoryPortOp op) {
1363 addValueName(op.getData(), legalize(op.getNameAttr()));
1366void Emitter::emitStatement(MemoryDebugPortOp op) {
1368 addValueName(op.getData(), legalize(op.getNameAttr()));
1371void Emitter::emitStatement(MemoryPortAccessOp op) {
1375 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1376 emitAttribute(port.getDirection());
1378 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
1381 auto *mem = port.getMemory().getDefiningOp();
1382 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1383 ps << legalize(seqMem.getNameAttr());
1385 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1389 emitExpression(op.getIndex());
1393 emitExpression(op.getClock());
1395 emitLocationAndNewLine(op);
1398void Emitter::emitStatement(DomainDefineOp op) {
1402 if (isa_and_nonnull<DomainCreateAnonOp>(op.getSrc().getDefiningOp()))
1406 emitAssignLike([&]() { emitExpression(op.getDest()); },
1407 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1409 emitLocationAndNewLine(op);
1412void Emitter::emitStatement(RefDefineOp op) {
1414 emitAssignLike([&]() { emitExpression(op.getDest()); },
1415 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1417 emitLocationAndNewLine(op);
1420void Emitter::emitStatement(RefForceOp op) {
1421 emitStatementFunctionOp(
PPExtString(
"force"), op);
1424void Emitter::emitStatement(RefForceInitialOp op) {
1426 auto constantPredicate =
1427 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1428 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1431 emitExpression(op.getPredicate());
1432 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1434 ps <<
"force_initial(";
1436 interleaveComma({op.getDest(), op.getSrc()});
1441 emitLocationAndNewLine(op);
1444void Emitter::emitStatement(RefReleaseOp op) {
1445 emitStatementFunctionOp(
PPExtString(
"release"), op);
1448void Emitter::emitStatement(RefReleaseInitialOp op) {
1450 auto constantPredicate =
1451 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1452 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1455 emitExpression(op.getPredicate());
1456 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1458 ps <<
"release_initial(";
1459 emitExpression(op.getDest());
1463 emitLocationAndNewLine(op);
1466void Emitter::emitStatement(LayerBlockOp op) {
1467 if (failed(requireVersion(
FIRVersion(3, 3, 0), op,
"layers")))
1470 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1471 emitLocationAndNewLine(op);
1472 auto *body = op.getBody();
1473 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1476void Emitter::emitStatement(InvalidValueOp op) {
1479 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1480 return use.getOperandNumber() == 1 &&
1481 isa<ConnectOp, MatchingConnectOp>(use.getOwner());
1487 auto name = circuitNamespace.newName(
"_invalid");
1488 addValueName(op, name);
1490 emitType(op.getType());
1491 emitLocationAndNewLine(op);
1497 emitLocationAndNewLine(op);
1500void Emitter::emitStatement(GenericIntrinsicOp op) {
1501 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"generic intrinsics")))
1505 emitGenericIntrinsic(op);
1508 auto name = circuitNamespace.newName(
"_gen_int");
1509 addValueName(op.getResult(), name);
1510 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(name); },
1511 [&]() { emitGenericIntrinsic(op); });
1513 emitLocationAndNewLine(op);
1516void Emitter::emitStatement(DomainCreateAnonOp op) {
1520void Emitter::emitStatement(DomainCreateOp op) {
1524 auto name = legalize(op.getNameAttr());
1525 addValueName(op.getResult(), name);
1530 auto fieldValues = op.getFieldValues();
1531 if (fieldValues.empty())
1534 ps <<
"(" << PP::ibox0;
1535 interleaveComma(fieldValues, [&](
auto value) { emitExpression(value); });
1536 ps <<
")" << PP::end;
1539 emitLocationAndNewLine(op);
1542void Emitter::emitExpression(Value value) {
1545 if (
auto name = lookupEmittedName(value)) {
1551 auto op = value.getDefiningOp();
1552 assert(op &&
"value must either be a block arg or the result of an op");
1553 TypeSwitch<Operation *>(op)
1556 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1557 OpenSubfieldOp, OpenSubindexOp, DomainSubfieldOp,
1559 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1560 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1561 EQPrimOp, NEQPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1563 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsResetPrimOp,
1564 AsClockPrimOp, CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp,
1567 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1568 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1569 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1570 UnresolvedPathOp, GenericIntrinsicOp, CatPrimOp, UnsafeDomainCastOp,
1571 UnknownValueOp, StringConcatOp, PropEqOp, BoolAndOp, BoolOrOp,
1574 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp,
1576 TimeOp>([&](
auto op) {
1577 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1579 .Default([&](
auto op) {
1580 emitOpError(op,
"not supported as expression");
1581 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1586void Emitter::emitExpression(ConstantOp op) {
1588 emitType(op.getType(),
false);
1595void Emitter::emitExpression(SpecialConstantOp op) {
1596 auto emitInner = [&]() {
1603 .
Case<ClockType>([&](
auto type) {
1608 .Case<ResetType>([&](
auto type) { emitInner(); })
1609 .Case<AsyncResetType>([&](
auto type) {
1610 ps <<
"asAsyncReset(";
1617void Emitter::emitExpression(SubfieldOp op) {
1618 BundleType type = op.getInput().getType();
1619 emitExpression(op.getInput());
1620 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1624void Emitter::emitExpression(SubindexOp op) {
1625 emitExpression(op.getInput());
1632void Emitter::emitExpression(SubaccessOp op) {
1633 emitExpression(op.getInput());
1635 emitExpression(op.getIndex());
1639void Emitter::emitExpression(OpenSubfieldOp op) {
1640 auto type = op.getInput().getType();
1641 emitExpression(op.getInput());
1642 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1646void Emitter::emitExpression(DomainSubfieldOp op) {
1647 emitExpression(op.getInput());
1648 ps <<
"." << legalize(op.getFieldName());
1651void Emitter::emitExpression(OpenSubindexOp op) {
1652 emitExpression(op.getInput());
1658void Emitter::emitExpression(RefSendOp op) {
1660 emitExpression(op.getBase());
1664void Emitter::emitExpression(RefResolveOp op) {
1666 emitExpression(op.getRef());
1670void Emitter::emitExpression(RefSubOp op) {
1671 emitExpression(op.getInput());
1673 .
Case<FVectorType>([&](
auto type) {
1679 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1682void Emitter::emitExpression(RWProbeOp op) {
1686 auto target = symInfos->get().irn.lookup(op.getTarget());
1688 if (target.isPort()) {
1689 auto mod = cast<FModuleOp>(target.getOp());
1690 auto port = target.getPort();
1691 base = mod.getArgument(port);
1693 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1696 emitExpression(base);
1699 auto fieldID = target.getField();
1700 auto type = base.getType();
1703 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1704 auto index = vecTy.getIndexForFieldID(fieldID);
1708 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1710 fieldID = subfieldID;
1712 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1713 auto index = bundleTy.getIndexForFieldID(fieldID);
1714 ps <<
"." << bundleTy.getElementName(index);
1715 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1717 fieldID = subfieldID;
1723void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1725void Emitter::emitExpression(UninferredResetCastOp op) {
1726 emitExpression(op.getInput());
1729void Emitter::emitExpression(FIntegerConstantOp op) {
1730 if (failed(requireVersion(
FIRVersion(3, 1, 0), op,
"Integers")))
1737void Emitter::emitExpression(BoolConstantOp op) {
1738 if (failed(requireVersion({6, 0, 0}, op,
"Bools")))
1740 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1743void Emitter::emitExpression(DoubleConstantOp op) {
1744 if (failed(requireVersion({6, 0, 0}, op,
"Doubles")))
1751 SmallString<16> str;
1752 op.getValueAttr().getValue().toString(str);
1757void Emitter::emitExpression(StringConstantOp op) {
1758 if (failed(requireVersion(
FIRVersion(3, 1, 0), op,
"Strings")))
1765void Emitter::emitExpression(ListCreateOp op) {
1766 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"Lists")))
1768 return emitLiteralExpression(op.getType(), op.getElements());
1771void Emitter::emitExpression(UnresolvedPathOp op) {
1772 if (failed(requireVersion({6, 0, 0}, op,
"Paths")))
1779void Emitter::emitExpression(GenericIntrinsicOp op) {
1780 if (failed(requireVersion(
FIRVersion(4, 0, 0), op,
"generic intrinsics")))
1782 emitGenericIntrinsic(op);
1785void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1787void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1788 ArrayRef<uint32_t> attrs) {
1789 ps << mnemonic <<
"(" << PP::ibox0;
1790 interleaveComma(op->getOperands());
1791 if (!op->getOperands().empty() && !attrs.empty())
1792 ps <<
"," << PP::space;
1793 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1794 ps <<
")" << PP::end;
1797void Emitter::emitExpression(CatPrimOp op) {
1798 size_t numOperands = op.getNumOperands();
1799 switch (numOperands) {
1802 emitType(op.getType(),
false);
1806 auto operand = op->getOperand(0);
1808 if (isa<UIntType>(operand.getType()))
1809 return emitExpression(operand);
1812 ps <<
"cat(" << PP::ibox0;
1813 emitExpression(op->getOperand(0));
1814 ps <<
"," << PP::space <<
"SInt<0>(0))" << PP::end;
1820 for (
size_t i = 0; i < numOperands - 1; ++i) {
1821 ps <<
"cat(" << PP::ibox0;
1822 emitExpression(op->getOperand(i));
1823 ps <<
"," << PP::space;
1826 emitExpression(op->getOperand(numOperands - 1));
1827 for (
size_t i = 0; i < numOperands - 1; ++i)
1828 ps <<
")" << PP::end;
1833void Emitter::emitExpression(UnsafeDomainCastOp op) {
1834 if (failed(requireVersion(
nextFIRVersion, op,
"unsafe_domain_cast")))
1836 ps <<
"unsafe_domain_cast(" << PP::ibox0;
1837 interleaveComma(op.getOperands(),
1838 [&](Value operand) { emitExpression(operand); });
1839 ps <<
")" << PP::end;
1842void Emitter::emitExpression(UnknownValueOp op) {
1844 requireVersion(
nextFIRVersion, op,
"unknown property expressions")))
1847 emitType(op.getType());
1851void Emitter::emitAttribute(MemDirAttr attr) {
1853 case MemDirAttr::Infer:
1856 case MemDirAttr::Read:
1859 case MemDirAttr::Write:
1862 case MemDirAttr::ReadWrite:
1868void Emitter::emitAttribute(RUWBehaviorAttr attr) {
1869 switch (attr.getValue()) {
1870 case RUWBehavior::Undefined:
1873 case RUWBehavior::Old:
1876 case RUWBehavior::New:
1883void Emitter::emitType(Type type,
bool includeConst) {
1884 if (includeConst &&
isConst(type))
1886 auto emitWidth = [&](std::optional<int32_t> width) {
1895 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1896 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1897 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1898 .Case<UIntType>([&](
auto type) {
1900 emitWidth(type.getWidth());
1902 .Case<SIntType>([&](
auto type) {
1904 emitWidth(type.getWidth());
1906 .Case<AnalogType>([&](
auto type) {
1908 emitWidth(type.getWidth());
1910 .Case<OpenBundleType, BundleType>([&](
auto type) {
1912 if (!type.getElements().empty())
1914 bool anyEmitted =
false;
1916 for (
auto &element : type.getElements()) {
1918 ps <<
"," << PP::space;
1922 ps << legalize(element.name);
1923 emitTypeWithColon(element.type);
1932 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1933 emitType(type.getElementType());
1938 .Case<RefType>([&](RefType type) {
1939 if (type.getForceable())
1942 ps.
cbox(2, IndentStyle::Block);
1944 emitType(type.getType());
1945 if (
auto layer = type.getLayer()) {
1948 emitSymbol(type.getLayer());
1953 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1954 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1955 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1956 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1957 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1958 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1959 .Case<ListType>([&](ListType type) {
1961 emitType(type.getElementType());
1964 .Case<DomainType>([&](DomainType type) {
1965 ps <<
"Domain of " <<
PPExtString(type.getName().getValue());
1967 .Default([&](
auto type) {
1968 llvm_unreachable(
"all types should be implemented");
1972void Emitter::emitDomains(Attribute attr, ArrayRef<PortInfo> ports) {
1975 auto domains = cast<ArrayAttr>(attr);
1976 if (domains.empty())
1980 interleaveComma(domains, [&](Attribute attr) {
1981 ps.
addAsString(ports[cast<IntegerAttr>(attr).getUInt()].name.getValue());
1989void Emitter::emitLocation(Location loc) {
1991 ps << PP::neverbreak;
1993 dyn_cast_or_null<FileLineColLoc, LocationAttr>(LocationAttr(loc))) {
1994 ps <<
" @[" << fileLoc.getFilename().getValue();
1995 if (
auto line = fileLoc.getLine()) {
1998 if (
auto col = fileLoc.getColumn()) {
2015 std::optional<size_t> targetLineLength,
2018 return module.emitError("--firrtl-version ")
2019 << version << " is below the minimum supported "
2020 << "version " << minimumFIRVersion;
2021 Emitter emitter(os, version,
2022 targetLineLength.value_or(defaultTargetLineLength));
2023 for (
auto &op : *
module.getBody()) {
2024 if (auto circuitOp = dyn_cast<CircuitOp>(op))
2025 emitter.emitCircuit(circuitOp);
2027 return emitter.finalize();
2032 "target-line-length",
2033 llvm::cl::desc(
"Target line length for emitted .fir"),
2034 llvm::cl::value_desc(
"number of chars"),
2035 llvm::cl::init(defaultTargetLineLength));
2038 llvm::cl::desc(
"FIRRTL version to target (e.g. \"3.0.0\"). "
2039 "Defaults to the latest supported version."),
2040 llvm::cl::value_desc(
"major.minor.patch"), llvm::cl::init(
""));
2041 static mlir::TranslateFromMLIRRegistration toFIR(
2042 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
2043 [](ModuleOp module, llvm::raw_ostream &os) -> mlir::LogicalResult {
2045 if (!firrtlVersionStr.empty()) {
2046 auto ver = FIRVersion::fromString(firrtlVersionStr);
2048 return module.emitError(
"invalid --firrtl-version: '")
2050 <<
"', expected format 'major.minor.patch'";
2053 return exportFIRFile(module, os, targetLineLength, version);
2055 [](mlir::DialectRegistry ®istry) {
2056 registry.insert<chirrtl::CHIRRTLDialect>();
2057 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.