21#include "mlir/IR/BuiltinOps.h"
22#include "mlir/Tools/mlir-translate/Translation.h"
23#include "llvm/ADT/APSInt.h"
24#include "llvm/ADT/StringSet.h"
25#include "llvm/ADT/TypeSwitch.h"
26#include "llvm/Support/Debug.h"
28#define DEBUG_TYPE "export-firrtl"
31using namespace firrtl;
32using namespace chirrtl;
33using namespace pretty;
42constexpr size_t defaultTargetLineLength = 80;
46 Emitter(llvm::raw_ostream &os,
FIRVersion version,
47 size_t targetLineLength = defaultTargetLineLength)
48 : pp(os, targetLineLength), ps(pp, saver), version(version) {
49 pp.setListener(&saver);
51 LogicalResult finalize();
54 void emitCircuit(CircuitOp op);
55 void emitModule(FModuleOp op);
56 void emitModule(FExtModuleOp op);
57 void emitModule(FIntModuleOp op);
58 void emitModulePorts(ArrayRef<PortInfo> ports,
59 Block::BlockArgListType arguments = {});
60 void emitModuleParameters(Operation *op, ArrayAttr parameters);
61 void emitDeclaration(DomainOp op);
62 void emitDeclaration(LayerOp op);
63 void emitDeclaration(OptionOp op);
64 void emitDeclaration(FormalOp op);
65 void emitDeclaration(SimulationOp op);
66 void emitFormalLike(Operation *op, StringRef keyword, StringAttr symName,
67 StringAttr moduleName, DictionaryAttr params);
68 void emitEnabledLayers(ArrayRef<Attribute> layers);
69 void emitKnownLayers(ArrayRef<Attribute> layers);
70 void 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(PropAssignOp op);
96 void emitStatement(InstanceOp op);
97 void emitStatement(InstanceChoiceOp op);
98 void emitStatement(AttachOp op);
99 void emitStatement(MemOp op);
100 void emitStatement(InvalidValueOp op);
101 void emitStatement(CombMemOp op);
102 void emitStatement(SeqMemOp op);
103 void emitStatement(MemoryPortOp op);
104 void emitStatement(MemoryDebugPortOp op);
105 void emitStatement(MemoryPortAccessOp op);
106 void emitStatement(DomainDefineOp op);
107 void emitStatement(RefDefineOp op);
108 void emitStatement(RefForceOp op);
109 void emitStatement(RefForceInitialOp op);
110 void emitStatement(RefReleaseOp op);
111 void emitStatement(RefReleaseInitialOp op);
112 void emitStatement(LayerBlockOp op);
113 void emitStatement(GenericIntrinsicOp op);
114 void emitStatement(DomainCreateAnonOp op);
115 void emitStatement(DomainCreateOp op);
118 void emitVerifStatement(T op, StringRef mnemonic);
119 void emitStatement(AssertOp op) { emitVerifStatement(op,
"assert"); }
120 void emitStatement(AssumeOp op) { emitVerifStatement(op,
"assume"); }
121 void emitStatement(CoverOp op) { emitVerifStatement(op,
"cover"); }
124 void emitExpression(Value value);
125 void emitExpression(ConstantOp op);
126 void emitExpression(SpecialConstantOp op);
127 void emitExpression(SubfieldOp op);
128 void emitExpression(SubindexOp op);
129 void emitExpression(SubaccessOp op);
130 void emitExpression(OpenSubfieldOp op);
131 void emitExpression(OpenSubindexOp op);
132 void emitExpression(RefResolveOp op);
133 void emitExpression(RefSendOp op);
134 void emitExpression(RefSubOp op);
135 void emitExpression(RWProbeOp op);
136 void emitExpression(RefCastOp op);
137 void emitExpression(UninferredResetCastOp op);
138 void emitExpression(ConstCastOp op);
139 void emitExpression(StringConstantOp op);
140 void emitExpression(FIntegerConstantOp op);
141 void emitExpression(BoolConstantOp op);
142 void emitExpression(DoubleConstantOp op);
143 void emitExpression(ListCreateOp op);
144 void emitExpression(UnresolvedPathOp op);
145 void emitExpression(GenericIntrinsicOp op);
146 void emitExpression(CatPrimOp op);
147 void emitExpression(UnsafeDomainCastOp op);
148 void emitExpression(UnknownValueOp op);
150 void emitPrimExpr(StringRef mnemonic, Operation *op,
151 ArrayRef<uint32_t> attrs = {});
153 void emitExpression(BitsPrimOp op) {
154 emitPrimExpr(
"bits", op, {op.getHi(), op.getLo()});
156 void emitExpression(HeadPrimOp op) {
157 emitPrimExpr(
"head", op, op.getAmount());
159 void emitExpression(TailPrimOp op) {
160 emitPrimExpr(
"tail", op, op.getAmount());
162 void emitExpression(PadPrimOp op) { emitPrimExpr(
"pad", op, op.getAmount()); }
163 void emitExpression(ShlPrimOp op) { emitPrimExpr(
"shl", op, op.getAmount()); }
164 void emitExpression(ShrPrimOp op) { emitPrimExpr(
"shr", op, op.getAmount()); }
166 void emitExpression(TimeOp op) {}
169#define HANDLE(OPTYPE, MNEMONIC) \
170 void emitExpression(OPTYPE op) { emitPrimExpr(MNEMONIC, op); }
185 HANDLE(DShlPrimOp,
"dshl");
186 HANDLE(DShlwPrimOp,
"dshlw");
187 HANDLE(DShrPrimOp,
"dshr");
189 HANDLE(AsSIntPrimOp,
"asSInt");
190 HANDLE(AsUIntPrimOp,
"asUInt");
191 HANDLE(AsAsyncResetPrimOp,
"asAsyncReset");
192 HANDLE(AsResetPrimOp,
"asReset");
193 HANDLE(AsClockPrimOp,
"asClock");
197 HANDLE(AndRPrimOp,
"andr");
199 HANDLE(XorRPrimOp,
"xorr");
203 void emitAttribute(MemDirAttr attr);
204 void emitAttribute(RUWBehaviorAttr attr);
207 void emitType(Type type,
bool includeConst =
true);
208 void emitTypeWithColon(Type type) {
209 ps << PP::space <<
":" << PP::nbsp;
214 void emitDomains(Attribute attr, ArrayRef<PortInfo> ports);
217 void emitLocation(Location loc);
218 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
219 template <
typename... Args>
220 void emitLocationAndNewLine(Args... args) {
223 ps << PP::neverbreak;
224 emitLocation(args...);
228 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
229 llvm::function_ref<
void()> emitRHS,
231 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
233 ps.scopedBox(PP::ibox2, [&]() {
235 ps << *wordBeforeLHS << PP::space;
239 ps << PP::space << syntax << PP::nbsp;
241 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
246 void emitSubExprIBox2(Value v) {
247 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
252 template <
typename Container,
typename EachFn>
253 void interleaveComma(
const Container &c, EachFn eachFn) {
254 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
259 void interleaveComma(ValueRange ops) {
260 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
263 void emitStatementFunctionOp(
PPExtString name, Operation *op) {
266 ps.scopedBox(PP::ibox0, [&]() {
267 interleaveComma(op->getOperands());
270 emitLocationAndNewLine(op);
273 template <
typename EachFn,
typename Range>
274 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
277 ps.scopedBox(PP::ibox0, [&]() {
278 interleaveComma(r, eachFn);
283 void emitLiteralExpression(Type type, ValueRange values) {
284 return emitLiteralExpression(type, values,
285 [&](Value v) { emitSubExprIBox2(v); });
289 void emitSymbol(SymbolRefAttr symbol) {
290 ps.ibox(2, IndentStyle::Block);
291 ps << symbol.getRootReference();
292 for (
auto nested : symbol.getNestedReferences()) {
295 ps << nested.getAttr();
302 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
303 encounteredError =
true;
304 return op->emitError(message);
308 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
309 encounteredError =
true;
310 return op->emitOpError(message);
315 std::optional<StringRef> lookupEmittedName(Value value) {
316 auto it = valueNames.find(value);
317 if (it != valueNames.end())
324 void emitPendingNewlineIfNeeded() {
325 if (pendingNewline) {
326 pendingNewline =
false;
330 void setPendingNewline() {
332 pendingNewline =
true;
335 void startStatement() { emitPendingNewlineIfNeeded(); }
353 bool pendingNewline =
false;
356 bool encounteredError =
false;
361 DenseMap<Value, StringRef> valueNames;
362 StringSet<> valueNamesStorage;
366 StringAttr legalize(StringAttr attr) {
367 StringRef str = attr.getValue();
368 if (str.empty() || !
isdigit(str.front()))
370 return StringAttr::get(attr.getContext(),
"`" + Twine(attr) +
"`");
373 void addValueName(Value value, StringAttr attr) {
374 valueNames.insert({value, attr.getValue()});
376 void addValueName(Value value, StringRef str) {
377 auto it = valueNamesStorage.insert(str);
378 valueNames.insert({value, it.first->getKey()});
380 void addForceable(Forceable op, StringAttr attr) {
381 addValueName(op.getData(), attr);
382 if (op.isForceable()) {
383 SmallString<32> rwName;
384 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
385 addValueName(op.getDataRef(), rwName);
394 SymbolTable symbolTable;
397 SymInfos(Operation *op) : symbolTable(op), istc(op) {}
399 std::optional<std::reference_wrapper<SymInfos>> symInfos;
406LogicalResult Emitter::finalize() {
return failure(encounteredError); }
409void Emitter::emitCircuit(CircuitOp op) {
410 circuitNamespace.add(op);
411 SymInfos circuitSymInfos(op);
412 symInfos = circuitSymInfos;
414 ps <<
"FIRRTL version ";
421 ps <<
"circuit " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
425 if (encounteredError)
427 TypeSwitch<Operation *>(&bodyOp)
428 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](
auto op) {
432 .Case<DomainOp, LayerOp, OptionOp, FormalOp, SimulationOp>(
433 [&](
auto op) { emitDeclaration(op); })
434 .Default([&](
auto op) {
435 emitOpError(op,
"not supported for emission inside circuit");
439 circuitNamespace.clear();
440 symInfos = std::nullopt;
443void Emitter::emitEnabledLayers(ArrayRef<Attribute> layers) {
444 for (
auto layer : layers) {
446 ps.
cbox(2, IndentStyle::Block);
447 ps <<
"enablelayer" << PP::space;
448 emitSymbol(cast<SymbolRefAttr>(layer));
453void Emitter::emitKnownLayers(ArrayRef<Attribute> layers) {
454 for (
auto layer : layers) {
456 ps.
cbox(2, IndentStyle::Block);
457 ps <<
"knownlayer" << PP::space;
458 emitSymbol(cast<SymbolRefAttr>(layer));
463void Emitter::emitRequirements(ArrayRef<Attribute> requirements) {
464 if (requirements.empty())
467 ps.
cbox(2, IndentStyle::Block);
468 ps <<
"requires" << PP::space;
469 llvm::interleaveComma(requirements, ps, [&](Attribute req) {
475void Emitter::emitParamAssign(ParamDeclAttr param, Operation *op,
476 std::optional<PPExtString> wordBeforeLHS) {
478 ps << *wordBeforeLHS << PP::nbsp;
480 ps <<
PPExtString(param.getName().strref()) << PP::nbsp <<
"=" << PP::nbsp;
481 emitParamValue(param.getValue(), op);
484void Emitter::emitParamValue(Attribute value, Operation *op) {
485 TypeSwitch<Attribute>(value)
486 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
487 .Case<FloatAttr>([&](
auto attr) {
489 attr.getValue().toString(str);
494 .Case<ArrayAttr>([&](
auto attr) {
497 interleaveComma(attr.getValue(),
498 [&](
auto element) { emitParamValue(element, op); });
502 .Case<DictionaryAttr>([&](
auto attr) {
505 interleaveComma(attr.getValue(), [&](
auto field) {
506 ps << PPExtString(field.getName()) << PP::nbsp <<
"=" << PP::nbsp;
507 emitParamValue(field.getValue(), op);
512 .Default([&](
auto attr) {
513 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
514 ps <<
"<unsupported-attr ";
520void Emitter::emitGenericIntrinsic(GenericIntrinsicOp op) {
524 ps << op.getIntrinsic();
526 auto params = op.getParameters();
527 if (!params.empty()) {
529 ps.scopedBox(PP::ibox0, [&]() {
531 params.getAsRange<ParamDeclAttr>(),
532 [&](ParamDeclAttr param) { emitParamAssign(param, op); });
537 if (op.getNumResults() != 0)
538 emitTypeWithColon(op.getResult().getType());
540 if (op.getNumOperands() != 0) {
541 ps <<
"," << PP::space;
542 ps.
scopedBox(PP::ibox0, [&]() { interleaveComma(op->getOperands()); });
549void Emitter::emitModule(FModuleOp op) {
551 ps.
cbox(4, IndentStyle::Block);
553 ps <<
"public" << PP::nbsp;
554 ps <<
"module " <<
PPExtString(legalize(op.getNameAttr()));
555 emitEnabledLayers(op.getLayers());
556 ps << PP::nbsp <<
":" << PP::end;
563 auto ports = op.getPorts();
564 emitModulePorts(ports, op.getArguments());
565 if (!ports.empty() && !op.getBodyBlock()->empty())
569 emitStatementsInBlock(*op.getBodyBlock());
572 valueNamesStorage.clear();
576void Emitter::emitModule(FExtModuleOp op) {
578 ps.
cbox(4, IndentStyle::Block);
579 ps <<
"extmodule " <<
PPExtString(legalize(op.getNameAttr()));
580 emitKnownLayers(op.getKnownLayers());
581 emitEnabledLayers(op.getLayers());
582 if (
auto reqs = op.getExternalRequirements())
583 emitRequirements(reqs.getValue());
584 ps << PP::nbsp <<
":" << PP::end;
591 auto ports = op.getPorts();
592 emitModulePorts(ports);
595 if (op.getDefname() && !op.getDefname()->empty()) {
597 ps <<
"defname = " <<
PPExtString(*op.getDefname());
602 emitModuleParameters(op, op.getParameters());
607void Emitter::emitModule(FIntModuleOp op) {
609 ps.
cbox(4, IndentStyle::Block);
610 ps <<
"intmodule " <<
PPExtString(legalize(op.getNameAttr()));
611 emitEnabledLayers(op.getLayers());
612 ps << PP::nbsp <<
":" << PP::end;
619 auto ports = op.getPorts();
620 emitModulePorts(ports);
623 ps <<
"intrinsic = " <<
PPExtString(op.getIntrinsic());
627 emitModuleParameters(op, op.getParameters());
634void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
635 Block::BlockArgListType arguments) {
637 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
639 const auto &port = ports[i];
640 ps << (port.direction == Direction::In ?
"input " :
"output ");
641 auto legalName = legalize(port.name);
642 if (!arguments.empty())
643 addValueName(arguments[i], legalName);
646 emitDomains(port.domains, ports);
647 emitLocation(ports[i].loc);
652void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
653 for (
auto param : parameters.getAsRange<ParamDeclAttr>()) {
655 emitParamAssign(param, op,
PPExtString(
"parameter"));
660void Emitter::emitDeclaration(DomainOp op) {
662 ps <<
"domain " <<
PPExtString(op.getSymName()) <<
" :";
663 emitLocationAndNewLine(op);
665 for (
auto attr : op.getFields()) {
666 auto fieldAttr = cast<DomainFieldAttr>(attr);
667 ps << PP::newline <<
PPExtString(fieldAttr.getName()) <<
" : ";
668 emitType(fieldAttr.getType());
674void Emitter::emitDeclaration(LayerOp op) {
676 ps <<
"layer " <<
PPExtString(op.getSymName()) <<
", "
677 <<
PPExtString(stringifyLayerConvention(op.getConvention()));
679 if (
auto outputFile = op->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
685 emitLocationAndNewLine(op);
687 for (
auto &bodyOp : op.getBody().getOps()) {
688 TypeSwitch<Operation *>(&bodyOp)
689 .Case<LayerOp>([&](
auto op) { emitDeclaration(op); })
690 .Default([&](
auto op) {
692 "not supported for emission inside layer definition");
699void Emitter::emitDeclaration(OptionOp op) {
701 ps <<
"option " <<
PPExtString(legalize(op.getSymNameAttr())) <<
" :";
704 for (
auto caseOp : op.getBody().getOps<OptionCaseOp>()) {
706 ps <<
PPExtString(legalize(caseOp.getSymNameAttr()));
707 emitLocation(caseOp);
710 ps << PP::newline << PP::newline;
714void Emitter::emitDeclaration(FormalOp op) {
715 emitFormalLike(op,
"formal", op.getSymNameAttr(),
716 op.getModuleNameAttr().getAttr(), op.getParameters());
720void Emitter::emitDeclaration(SimulationOp op) {
721 emitFormalLike(op,
"simulation", op.getSymNameAttr(),
722 op.getModuleNameAttr().getAttr(), op.getParameters());
726void Emitter::emitFormalLike(Operation *op, StringRef keyword,
727 StringAttr symName, StringAttr moduleName,
728 DictionaryAttr params) {
730 ps.
cbox(4, IndentStyle::Block);
731 ps << keyword <<
" " <<
PPExtString(legalize(symName));
733 ps << PP::nbsp <<
":" << PP::end;
738 for (
auto param : params) {
740 ps <<
PPExtString(param.getName()) << PP::nbsp <<
"=" << PP::nbsp;
741 emitParamValue(param.getValue(), op);
755 return (
isExpression(op) && !isa<InvalidValueOp>(op)) ||
756 (isa<GenericIntrinsicOp>(op) && op->hasOneUse() &&
760void Emitter::emitStatementsInBlock(Block &block) {
761 for (
auto &bodyOp : block) {
762 if (encounteredError)
766 TypeSwitch<Operation *>(&bodyOp)
767 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
768 PrintFOp, FPrintFOp, FFlushOp, AssertOp, AssumeOp, CoverOp,
769 ConnectOp, MatchingConnectOp, PropAssignOp, InstanceOp,
770 InstanceChoiceOp, AttachOp, MemOp, InvalidValueOp, SeqMemOp,
771 CombMemOp, MemoryPortOp, MemoryDebugPortOp, MemoryPortAccessOp,
772 DomainDefineOp, RefDefineOp, RefForceOp, RefForceInitialOp,
773 RefReleaseOp, RefReleaseInitialOp, LayerBlockOp,
774 GenericIntrinsicOp, DomainCreateAnonOp, DomainCreateOp>(
775 [&](
auto op) { emitStatement(op); })
776 .Default([&](
auto op) {
778 ps <<
"// operation " <<
PPExtString(op->getName().getStringRef());
780 emitOpError(op,
"not supported as statement");
785void Emitter::emitStatement(WhenOp op) {
788 emitExpression(op.getCondition());
790 emitLocationAndNewLine(op);
791 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
793 if (!op.hasElseRegion())
800 auto &elseBlock = op.getElseBlock();
801 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
802 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
803 emitStatement(whenOp);
810 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
813void Emitter::emitStatement(WireOp op) {
814 auto legalName = legalize(op.getNameAttr());
815 addForceable(op, legalName);
819 emitTypeWithColon(op.getResult().getType());
821 emitLocationAndNewLine(op);
824void Emitter::emitStatement(RegOp op) {
825 auto legalName = legalize(op.getNameAttr());
826 addForceable(op, legalName);
830 emitTypeWithColon(op.getResult().getType());
831 ps <<
"," << PP::space;
832 emitExpression(op.getClockVal());
834 emitLocationAndNewLine(op);
837void Emitter::emitStatement(RegResetOp op) {
838 auto legalName = legalize(op.getNameAttr());
839 addForceable(op, legalName);
843 ps <<
"regreset " << legalName;
844 emitTypeWithColon(op.getResult().getType());
845 ps <<
"," << PP::space;
846 emitExpression(op.getClockVal());
847 ps <<
"," << PP::space;
848 emitExpression(op.getResetSignal());
849 ps <<
"," << PP::space;
850 emitExpression(op.getResetValue());
854 ps <<
"reg " << legalName;
855 emitTypeWithColon(op.getResult().getType());
856 ps <<
"," << PP::space;
857 emitExpression(op.getClockVal());
858 ps << PP::space <<
"with :";
860 ps << PP::neverbreak;
863 ps <<
"reset => (" << PP::ibox0;
864 emitExpression(op.getResetSignal());
865 ps <<
"," << PP::space;
866 emitExpression(op.getResetValue());
867 ps <<
")" << PP::end;
870 emitLocationAndNewLine(op);
873void Emitter::emitStatement(NodeOp op) {
874 auto legalName = legalize(op.getNameAttr());
875 addForceable(op, legalName);
877 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(legalName); },
878 [&]() { emitExpression(op.getInput()); });
879 emitLocationAndNewLine(op);
882void Emitter::emitStatement(StopOp op) {
885 ps <<
"stop(" << PP::ibox0;
886 emitExpression(op.getClock());
887 ps <<
"," << PP::space;
888 emitExpression(op.getCond());
889 ps <<
"," << PP::space;
891 ps <<
")" << PP::end;
892 if (!op.getName().empty()) {
893 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
896 emitLocationAndNewLine(op);
899void Emitter::emitStatement(SkipOp op) {
902 emitLocationAndNewLine(op);
905void Emitter::emitFormatString(Operation *op, StringRef origFormatString,
906 OperandRange substitutionOperands,
907 llvm::SmallVectorImpl<Value> &substitutions) {
916 SmallString<64> formatString;
917 for (
size_t i = 0, e = origFormatString.size(), opIdx = 0; i != e; ++i) {
918 auto c = origFormatString[i];
921 formatString.push_back(c);
924 SmallString<6> width;
925 c = origFormatString[++i];
928 c = origFormatString[++i];
937 formatString.append(width);
940 substitutions.push_back(substitutionOperands[opIdx++]);
943 formatString.push_back(c);
948 if (origFormatString.slice(i, i + 4) ==
"{{}}") {
949 formatString.append(
"{{");
950 TypeSwitch<Operation *>(substitutionOperands[opIdx++].getDefiningOp())
952 [&](
auto time) { formatString.append(
"SimulationTime"); })
953 .Case<HierarchicalModuleNameOp>([&](
auto time) {
954 formatString.append(
"HierarchicalModuleName");
957 emitError(op,
"unsupported fstring substitution type");
959 formatString.append(
"}}");
964 formatString.push_back(c);
970void Emitter::emitStatement(PrintFOp op) {
973 ps <<
"printf(" << PP::ibox0;
974 emitExpression(op.getClock());
975 ps <<
"," << PP::space;
976 emitExpression(op.getCond());
977 ps <<
"," << PP::space;
979 SmallVector<Value, 4> substitutions;
980 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
982 for (
auto operand : substitutions) {
983 ps <<
"," << PP::space;
984 emitExpression(operand);
986 ps <<
")" << PP::end;
987 if (!op.getName().empty()) {
988 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
991 emitLocationAndNewLine(op);
994void Emitter::emitStatement(FPrintFOp op) {
997 ps <<
"fprintf(" << PP::ibox0;
998 emitExpression(op.getClock());
999 ps <<
"," << PP::space;
1000 emitExpression(op.getCond());
1001 ps <<
"," << PP::space;
1003 SmallVector<Value, 4> outputFileSubstitutions;
1004 emitFormatString(op, op.getOutputFile(), op.getOutputFileSubstitutions(),
1005 outputFileSubstitutions);
1006 if (!outputFileSubstitutions.empty()) {
1007 ps <<
"," << PP::space;
1008 interleaveComma(outputFileSubstitutions);
1011 ps <<
"," << PP::space;
1012 SmallVector<Value, 4> substitutions;
1013 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
1015 if (!substitutions.empty()) {
1016 ps <<
"," << PP::space;
1017 interleaveComma(substitutions);
1020 ps <<
")" << PP::end;
1021 if (!op.getName().empty()) {
1022 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1025 emitLocationAndNewLine(op);
1028void Emitter::emitStatement(FFlushOp op) {
1031 ps <<
"fflush(" << PP::ibox0;
1032 emitExpression(op.getClock());
1033 ps <<
"," << PP::space;
1034 emitExpression(op.getCond());
1035 if (op.getOutputFileAttr()) {
1036 ps <<
"," << PP::space;
1037 SmallVector<Value, 4> substitutions;
1038 emitFormatString(op, op.getOutputFileAttr(),
1039 op.getOutputFileSubstitutions(), substitutions);
1040 if (!substitutions.empty()) {
1041 ps <<
"," << PP::space;
1042 interleaveComma(substitutions);
1045 ps <<
")" << PP::end;
1047 emitLocationAndNewLine(op);
1051void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
1054 ps << mnemonic <<
"(" << PP::ibox0;
1055 emitExpression(op.getClock());
1056 ps <<
"," << PP::space;
1057 emitExpression(op.getPredicate());
1058 ps <<
"," << PP::space;
1059 emitExpression(op.getEnable());
1060 ps <<
"," << PP::space;
1062 ps <<
")" << PP::end;
1063 if (!op.getName().empty()) {
1064 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1067 emitLocationAndNewLine(op);
1070void Emitter::emitStatement(ConnectOp op) {
1074 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1075 ps <<
"invalidate" << PP::space;
1076 emitExpression(op.getDest());
1078 ps <<
"connect" << PP::space;
1079 emitExpression(op.getDest());
1080 ps <<
"," << PP::space;
1081 emitExpression(op.getSrc());
1085 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1086 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1088 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1091 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1094 emitLocationAndNewLine(op);
1097void Emitter::emitStatement(MatchingConnectOp op) {
1101 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1102 ps <<
"invalidate" << PP::space;
1103 emitExpression(op.getDest());
1105 ps <<
"connect" << PP::space;
1106 emitExpression(op.getDest());
1107 ps <<
"," << PP::space;
1108 emitExpression(op.getSrc());
1112 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1113 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1115 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1118 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1121 emitLocationAndNewLine(op);
1124void Emitter::emitStatement(PropAssignOp op) {
1127 ps <<
"propassign" << PP::space;
1128 interleaveComma(op.getOperands());
1130 emitLocationAndNewLine(op);
1133void Emitter::emitStatement(InstanceOp op) {
1135 auto legalName = legalize(op.getNameAttr());
1137 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
1138 emitLocationAndNewLine(op);
1142 SmallString<16> portName(legalName);
1143 portName.push_back(
'.');
1144 unsigned baseLen = portName.size();
1145 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1146 portName.append(legalize(op.getPortNameAttr(i)));
1147 addValueName(op.getResult(i), portName);
1148 portName.resize(baseLen);
1152void Emitter::emitStatement(InstanceChoiceOp op) {
1154 auto legalName = legalize(op.getNameAttr());
1155 ps <<
"instchoice " <<
PPExtString(legalName) <<
" of "
1156 <<
PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
1157 <<
PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
1160 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
1162 ps <<
PPExtString(legalize(optSym.getLeafReference()));
1167 setPendingNewline();
1169 SmallString<16> portName(legalName);
1170 portName.push_back(
'.');
1171 unsigned baseLen = portName.size();
1172 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1173 portName.append(legalize(op.getPortNameAttr(i)));
1174 addValueName(op.getResult(i), portName);
1175 portName.resize(baseLen);
1179void Emitter::emitStatement(AttachOp op) {
1180 emitStatementFunctionOp(
PPExtString(
"attach"), op);
1183void Emitter::emitStatement(MemOp op) {
1184 auto legalName = legalize(op.getNameAttr());
1185 SmallString<16> portName(legalName);
1186 portName.push_back(
'.');
1187 auto portNameBaseLen = portName.size();
1188 for (
auto result :
llvm::zip(op.getResults(), op.getPortNames())) {
1189 portName.resize(portNameBaseLen);
1190 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
1191 addValueName(std::get<0>(result), portName);
1196 emitLocationAndNewLine(op);
1199 ps <<
"data-type => ";
1200 emitType(op.getDataType());
1205 ps <<
"read-latency => ";
1208 ps <<
"write-latency => ";
1212 SmallString<16> reader, writer, readwriter;
1213 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
1214 auto add = [&](SmallString<16> &to, StringAttr name) {
1217 to.append(name.getValue());
1219 switch (port.second) {
1220 case MemOp::PortKind::Read:
1221 add(reader, legalize(port.first));
1223 case MemOp::PortKind::Write:
1224 add(writer, legalize(port.first));
1226 case MemOp::PortKind::ReadWrite:
1227 add(readwriter, legalize(port.first));
1229 case MemOp::PortKind::Debug:
1230 emitOpError(op,
"has unsupported 'debug' port");
1234 if (!reader.empty())
1235 ps <<
"reader => " << reader << PP::newline;
1236 if (!writer.empty())
1237 ps <<
"writer => " << writer << PP::newline;
1238 if (!readwriter.empty())
1239 ps <<
"readwriter => " << readwriter << PP::newline;
1241 ps <<
"read-under-write => ";
1242 emitAttribute(op.getRuwAttr());
1243 setPendingNewline();
1247void Emitter::emitStatement(SeqMemOp op) {
1250 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
1251 emitTypeWithColon(op.getType());
1252 ps <<
"," << PP::space;
1253 emitAttribute(op.getRuwAttr());
1255 emitLocationAndNewLine(op);
1258void Emitter::emitStatement(CombMemOp op) {
1261 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
1262 emitTypeWithColon(op.getType());
1264 emitLocationAndNewLine(op);
1267void Emitter::emitStatement(MemoryPortOp op) {
1269 addValueName(op.getData(), legalize(op.getNameAttr()));
1272void Emitter::emitStatement(MemoryDebugPortOp op) {
1274 addValueName(op.getData(), legalize(op.getNameAttr()));
1277void Emitter::emitStatement(MemoryPortAccessOp op) {
1281 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1282 emitAttribute(port.getDirection());
1284 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
1287 auto *mem = port.getMemory().getDefiningOp();
1288 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1289 ps << legalize(seqMem.getNameAttr());
1291 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1295 emitExpression(op.getIndex());
1299 emitExpression(op.getClock());
1301 emitLocationAndNewLine(op);
1304void Emitter::emitStatement(DomainDefineOp op) {
1306 if (isa_and_nonnull<DomainCreateAnonOp>(op.getSrc().getDefiningOp()))
1310 emitAssignLike([&]() { emitExpression(op.getDest()); },
1311 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1313 emitLocationAndNewLine(op);
1316void Emitter::emitStatement(RefDefineOp op) {
1318 emitAssignLike([&]() { emitExpression(op.getDest()); },
1319 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1321 emitLocationAndNewLine(op);
1324void Emitter::emitStatement(RefForceOp op) {
1325 emitStatementFunctionOp(
PPExtString(
"force"), op);
1328void Emitter::emitStatement(RefForceInitialOp op) {
1330 auto constantPredicate =
1331 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1332 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1335 emitExpression(op.getPredicate());
1336 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1338 ps <<
"force_initial(";
1340 interleaveComma({op.getDest(), op.getSrc()});
1345 emitLocationAndNewLine(op);
1348void Emitter::emitStatement(RefReleaseOp op) {
1349 emitStatementFunctionOp(
PPExtString(
"release"), op);
1352void Emitter::emitStatement(RefReleaseInitialOp op) {
1354 auto constantPredicate =
1355 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1356 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1359 emitExpression(op.getPredicate());
1360 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1362 ps <<
"release_initial(";
1363 emitExpression(op.getDest());
1367 emitLocationAndNewLine(op);
1370void Emitter::emitStatement(LayerBlockOp op) {
1372 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1373 emitLocationAndNewLine(op);
1374 auto *body = op.getBody();
1375 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1378void Emitter::emitStatement(InvalidValueOp op) {
1381 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1382 return use.getOperandNumber() == 1 &&
1383 isa<ConnectOp, MatchingConnectOp>(use.getOwner());
1389 auto name = circuitNamespace.newName(
"_invalid");
1390 addValueName(op, name);
1392 emitType(op.getType());
1393 emitLocationAndNewLine(op);
1399 emitLocationAndNewLine(op);
1402void Emitter::emitStatement(GenericIntrinsicOp op) {
1405 emitGenericIntrinsic(op);
1408 auto name = circuitNamespace.newName(
"_gen_int");
1409 addValueName(op.getResult(), name);
1410 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(name); },
1411 [&]() { emitGenericIntrinsic(op); });
1413 emitLocationAndNewLine(op);
1416void Emitter::emitStatement(DomainCreateAnonOp op) {
1420void Emitter::emitStatement(DomainCreateOp op) {
1422 auto name = legalize(op.getNameAttr());
1423 addValueName(op.getResult(), name);
1426 emitLocationAndNewLine(op);
1429void Emitter::emitExpression(Value value) {
1432 if (
auto name = lookupEmittedName(value)) {
1438 auto op = value.getDefiningOp();
1439 assert(op &&
"value must either be a block arg or the result of an op");
1440 TypeSwitch<Operation *>(op)
1443 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1444 OpenSubfieldOp, OpenSubindexOp,
1446 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1447 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1448 EQPrimOp, NEQPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1450 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsResetPrimOp,
1451 AsClockPrimOp, CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp,
1454 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1455 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1456 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1457 UnresolvedPathOp, GenericIntrinsicOp, CatPrimOp, UnsafeDomainCastOp,
1460 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp,
1462 TimeOp>([&](
auto op) {
1463 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1465 .Default([&](
auto op) {
1466 emitOpError(op,
"not supported as expression");
1467 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1472void Emitter::emitExpression(ConstantOp op) {
1474 emitType(op.getType(),
false);
1481void Emitter::emitExpression(SpecialConstantOp op) {
1482 auto emitInner = [&]() {
1489 .
Case<ClockType>([&](
auto type) {
1494 .Case<ResetType>([&](
auto type) { emitInner(); })
1495 .Case<AsyncResetType>([&](
auto type) {
1496 ps <<
"asAsyncReset(";
1503void Emitter::emitExpression(SubfieldOp op) {
1504 BundleType type = op.getInput().getType();
1505 emitExpression(op.getInput());
1506 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1510void Emitter::emitExpression(SubindexOp op) {
1511 emitExpression(op.getInput());
1518void Emitter::emitExpression(SubaccessOp op) {
1519 emitExpression(op.getInput());
1521 emitExpression(op.getIndex());
1525void Emitter::emitExpression(OpenSubfieldOp op) {
1526 auto type = op.getInput().getType();
1527 emitExpression(op.getInput());
1528 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1531void Emitter::emitExpression(OpenSubindexOp op) {
1532 emitExpression(op.getInput());
1538void Emitter::emitExpression(RefSendOp op) {
1540 emitExpression(op.getBase());
1544void Emitter::emitExpression(RefResolveOp op) {
1546 emitExpression(op.getRef());
1550void Emitter::emitExpression(RefSubOp op) {
1551 emitExpression(op.getInput());
1553 .
Case<FVectorType>([&](
auto type) {
1559 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1562void Emitter::emitExpression(RWProbeOp op) {
1566 auto target = symInfos->get().irn.lookup(op.getTarget());
1568 if (target.isPort()) {
1569 auto mod = cast<FModuleOp>(target.getOp());
1570 auto port = target.getPort();
1571 base = mod.getArgument(port);
1573 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1576 emitExpression(base);
1579 auto fieldID = target.getField();
1580 auto type = base.getType();
1583 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1584 auto index = vecTy.getIndexForFieldID(fieldID);
1588 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1590 fieldID = subfieldID;
1592 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1593 auto index = bundleTy.getIndexForFieldID(fieldID);
1594 ps <<
"." << bundleTy.getElementName(index);
1595 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1597 fieldID = subfieldID;
1603void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1605void Emitter::emitExpression(UninferredResetCastOp op) {
1606 emitExpression(op.getInput());
1609void Emitter::emitExpression(FIntegerConstantOp op) {
1615void Emitter::emitExpression(BoolConstantOp op) {
1616 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1619void Emitter::emitExpression(DoubleConstantOp op) {
1625 SmallString<16> str;
1626 op.getValueAttr().getValue().toString(str);
1631void Emitter::emitExpression(StringConstantOp op) {
1637void Emitter::emitExpression(ListCreateOp op) {
1638 return emitLiteralExpression(op.getType(), op.getElements());
1641void Emitter::emitExpression(UnresolvedPathOp op) {
1647void Emitter::emitExpression(GenericIntrinsicOp op) {
1648 emitGenericIntrinsic(op);
1651void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1653void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1654 ArrayRef<uint32_t> attrs) {
1655 ps << mnemonic <<
"(" << PP::ibox0;
1656 interleaveComma(op->getOperands());
1657 if (!op->getOperands().empty() && !attrs.empty())
1658 ps <<
"," << PP::space;
1659 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1660 ps <<
")" << PP::end;
1663void Emitter::emitExpression(CatPrimOp op) {
1664 size_t numOperands = op.getNumOperands();
1665 switch (numOperands) {
1668 emitType(op.getType(),
false);
1672 auto operand = op->getOperand(0);
1674 if (isa<UIntType>(operand.getType()))
1675 return emitExpression(operand);
1678 ps <<
"cat(" << PP::ibox0;
1679 emitExpression(op->getOperand(0));
1680 ps <<
"," << PP::space <<
"SInt<0>(0))" << PP::end;
1686 for (
size_t i = 0; i < numOperands - 1; ++i) {
1687 ps <<
"cat(" << PP::ibox0;
1688 emitExpression(op->getOperand(i));
1689 ps <<
"," << PP::space;
1692 emitExpression(op->getOperand(numOperands - 1));
1693 for (
size_t i = 0; i < numOperands - 1; ++i)
1694 ps <<
")" << PP::end;
1699void Emitter::emitExpression(UnsafeDomainCastOp op) {
1700 ps <<
"unsafe_domain_cast(" << PP::ibox0;
1701 interleaveComma(op.getOperands(),
1702 [&](Value operand) { emitExpression(operand); });
1703 ps <<
")" << PP::end;
1706void Emitter::emitExpression(UnknownValueOp op) {
1708 emitType(op.getType());
1712void Emitter::emitAttribute(MemDirAttr attr) {
1714 case MemDirAttr::Infer:
1717 case MemDirAttr::Read:
1720 case MemDirAttr::Write:
1723 case MemDirAttr::ReadWrite:
1729void Emitter::emitAttribute(RUWBehaviorAttr attr) {
1730 switch (attr.getValue()) {
1731 case RUWBehavior::Undefined:
1734 case RUWBehavior::Old:
1737 case RUWBehavior::New:
1744void Emitter::emitType(Type type,
bool includeConst) {
1745 if (includeConst &&
isConst(type))
1747 auto emitWidth = [&](std::optional<int32_t> width) {
1756 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1757 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1758 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1759 .Case<UIntType>([&](
auto type) {
1761 emitWidth(type.getWidth());
1763 .Case<SIntType>([&](
auto type) {
1765 emitWidth(type.getWidth());
1767 .Case<AnalogType>([&](
auto type) {
1769 emitWidth(type.getWidth());
1771 .Case<OpenBundleType, BundleType>([&](
auto type) {
1773 if (!type.getElements().empty())
1775 bool anyEmitted =
false;
1777 for (
auto &element : type.getElements()) {
1779 ps <<
"," << PP::space;
1783 ps << legalize(element.name);
1784 emitTypeWithColon(element.type);
1793 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1794 emitType(type.getElementType());
1799 .Case<RefType>([&](RefType type) {
1800 if (type.getForceable())
1803 ps.
cbox(2, IndentStyle::Block);
1805 emitType(type.getType());
1806 if (
auto layer = type.getLayer()) {
1809 emitSymbol(type.getLayer());
1814 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1815 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1816 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1817 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1818 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1819 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1820 .Case<ListType>([&](ListType type) {
1822 emitType(type.getElementType());
1825 .Case<DomainType>([&](DomainType type) { ps <<
"Domain"; })
1826 .Default([&](
auto type) {
1827 llvm_unreachable(
"all types should be implemented");
1831void Emitter::emitDomains(Attribute attr, ArrayRef<PortInfo> ports) {
1834 if (
auto domains = dyn_cast<ArrayAttr>(attr)) {
1835 if (domains.empty())
1839 interleaveComma(domains, [&](Attribute attr) {
1841 ports[cast<IntegerAttr>(attr).getUInt()].name.getValue());
1846 auto kind = cast<FlatSymbolRefAttr>(attr);
1853void Emitter::emitLocation(Location loc) {
1855 ps << PP::neverbreak;
1857 dyn_cast_or_null<FileLineColLoc, LocationAttr>(LocationAttr(loc))) {
1858 ps <<
" @[" << fileLoc.getFilename().getValue();
1859 if (
auto line = fileLoc.getLine()) {
1862 if (
auto col = fileLoc.getColumn()) {
1879 std::optional<size_t> targetLineLength,
1881 Emitter emitter(os, version,
1882 targetLineLength.value_or(defaultTargetLineLength));
1883 for (
auto &op : *
module.getBody()) {
1884 if (auto circuitOp = dyn_cast<CircuitOp>(op))
1885 emitter.emitCircuit(circuitOp);
1887 return emitter.finalize();
1892 "target-line-length",
1893 llvm::cl::desc(
"Target line length for emitted .fir"),
1894 llvm::cl::value_desc(
"number of chars"),
1895 llvm::cl::init(defaultTargetLineLength));
1896 static mlir::TranslateFromMLIRRegistration toFIR(
1897 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
1898 [](ModuleOp module, llvm::raw_ostream &os) {
1901 [](mlir::DialectRegistry ®istry) {
1902 registry.insert<chirrtl::CHIRRTLDialect>();
1903 registry.insert<firrtl::FIRRTLDialect>();
assert(baseType &&"element must be base type")
#define HANDLE(OPTYPE, OPKIND)
static bool isEmittedInline(Operation *op)
Check if an operation is inlined into the emission of their users.
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Block * getBodyBlock(FModuleLike mod)
This class implements the same functionality as TypeSwitch except that it uses firrtl::type_dyn_cast ...
FIRRTLTypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
This class represents a collection of InnerSymbolTable's.
void space()
Add a breakable space.
void cbox(int32_t offset=0, IndentStyle style=IndentStyle::Visual)
Start a consistent group with specified offset.
void zerobreak()
Add a break that is zero-wide if not broken.
Wrap a PrettyPrinter with TokenBuilder features as well as operator<<'s.
auto scopedBox(T &&t, Callable &&c, Token close=EndToken())
Open a box, invoke the lambda, and close it after.
TokenStream & addAsString(T &&t)
General-purpose "format this" helper, for types not supported by operator<< yet.
TokenStream & writeQuotedEscaped(StringRef str, bool useHexEscapes=false, StringRef left="\"", StringRef right="\"")
PrettyPrinter::Listener that saves strings while live.
mlir::LogicalResult exportFIRFile(mlir::ModuleOp module, llvm::raw_ostream &os, std::optional< size_t > targetLineLength, FIRVersion version)
constexpr FIRVersion exportFIRVersion
The version of FIRRTL that the exporter produces.
void registerToFIRFileTranslation()
bool isConst(Type type)
Returns true if this is a 'const' type whose value is guaranteed to be unchanging at circuit executio...
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
The namespace of a CircuitOp, generally inhabited by modules.
The FIRRTL specification version.
This class represents the namespace in which InnerRef's can be resolved.
String wrapper to indicate string has external storage.