21#include "mlir/IR/BuiltinOps.h"
22#include "mlir/Tools/mlir-translate/Translation.h"
23#include "llvm/ADT/APSInt.h"
24#include "llvm/ADT/StringSet.h"
25#include "llvm/ADT/TypeSwitch.h"
26#include "llvm/Support/Debug.h"
28#define DEBUG_TYPE "export-firrtl"
31using namespace firrtl;
32using namespace chirrtl;
33using namespace pretty;
42constexpr size_t defaultTargetLineLength = 80;
46 Emitter(llvm::raw_ostream &os,
FIRVersion version,
47 size_t targetLineLength = defaultTargetLineLength)
48 : pp(os, targetLineLength), ps(pp, saver), version(version) {
49 pp.setListener(&saver);
51 LogicalResult finalize();
54 void emitCircuit(CircuitOp op);
55 void emitModule(FModuleOp op);
56 void emitModule(FExtModuleOp op);
57 void emitModule(FIntModuleOp op);
58 void emitModulePorts(ArrayRef<PortInfo> ports,
59 Block::BlockArgListType arguments = {});
60 void emitModuleParameters(Operation *op, ArrayAttr parameters);
61 void emitDeclaration(DomainOp op);
62 void emitDeclaration(LayerOp op);
63 void emitDeclaration(OptionOp op);
64 void emitDeclaration(FormalOp op);
65 void emitDeclaration(SimulationOp op);
66 void emitFormalLike(Operation *op, StringRef keyword, StringAttr symName,
67 StringAttr moduleName, DictionaryAttr params);
68 void emitEnabledLayers(ArrayRef<Attribute> layers);
69 void emitKnownLayers(ArrayRef<Attribute> layers);
70 void emitParamAssign(ParamDeclAttr param, Operation *op,
71 std::optional<PPExtString> wordBeforeLHS = std::nullopt);
72 void emitParamValue(Attribute value, Operation *op);
74 void emitGenericIntrinsic(GenericIntrinsicOp op);
77 void emitStatementsInBlock(
Block &block);
78 void emitStatement(WhenOp op);
79 void emitStatement(WireOp op);
80 void emitStatement(RegOp op);
81 void emitStatement(RegResetOp op);
82 void emitStatement(NodeOp op);
83 void emitStatement(StopOp op);
84 void emitStatement(SkipOp op);
85 void emitFormatString(Operation *op, StringRef formatString, OperandRange ops,
86 llvm::SmallVectorImpl<Value> &substitutions);
88 void emitPrintfLike(T op, StringAttr fileName);
89 void emitStatement(PrintFOp op);
90 void emitStatement(FPrintFOp op);
91 void emitStatement(FFlushOp op);
92 void emitStatement(ConnectOp op);
93 void emitStatement(MatchingConnectOp op);
94 void emitStatement(PropAssignOp op);
95 void emitStatement(InstanceOp op);
96 void emitStatement(InstanceChoiceOp op);
97 void emitStatement(AttachOp op);
98 void emitStatement(MemOp op);
99 void emitStatement(InvalidValueOp op);
100 void emitStatement(CombMemOp op);
101 void emitStatement(SeqMemOp op);
102 void emitStatement(MemoryPortOp op);
103 void emitStatement(MemoryDebugPortOp op);
104 void emitStatement(MemoryPortAccessOp op);
105 void emitStatement(RefDefineOp op);
106 void emitStatement(RefForceOp op);
107 void emitStatement(RefForceInitialOp op);
108 void emitStatement(RefReleaseOp op);
109 void emitStatement(RefReleaseInitialOp op);
110 void emitStatement(LayerBlockOp op);
111 void emitStatement(GenericIntrinsicOp op);
114 void emitVerifStatement(T op, StringRef mnemonic);
115 void emitStatement(AssertOp op) { emitVerifStatement(op,
"assert"); }
116 void emitStatement(AssumeOp op) { emitVerifStatement(op,
"assume"); }
117 void emitStatement(CoverOp op) { emitVerifStatement(op,
"cover"); }
120 void emitExpression(Value value);
121 void emitExpression(ConstantOp op);
122 void emitExpression(SpecialConstantOp op);
123 void emitExpression(SubfieldOp op);
124 void emitExpression(SubindexOp op);
125 void emitExpression(SubaccessOp op);
126 void emitExpression(OpenSubfieldOp op);
127 void emitExpression(OpenSubindexOp op);
128 void emitExpression(RefResolveOp op);
129 void emitExpression(RefSendOp op);
130 void emitExpression(RefSubOp op);
131 void emitExpression(RWProbeOp op);
132 void emitExpression(RefCastOp op);
133 void emitExpression(UninferredResetCastOp op);
134 void emitExpression(ConstCastOp op);
135 void emitExpression(StringConstantOp op);
136 void emitExpression(FIntegerConstantOp op);
137 void emitExpression(BoolConstantOp op);
138 void emitExpression(DoubleConstantOp op);
139 void emitExpression(ListCreateOp op);
140 void emitExpression(UnresolvedPathOp op);
141 void emitExpression(GenericIntrinsicOp op);
142 void emitExpression(CatPrimOp op);
143 void emitExpression(UnsafeDomainCastOp op);
145 void emitPrimExpr(StringRef mnemonic, Operation *op,
146 ArrayRef<uint32_t> attrs = {});
148 void emitExpression(BitsPrimOp op) {
149 emitPrimExpr(
"bits", op, {op.getHi(), op.getLo()});
151 void emitExpression(HeadPrimOp op) {
152 emitPrimExpr(
"head", op, op.getAmount());
154 void emitExpression(TailPrimOp op) {
155 emitPrimExpr(
"tail", op, op.getAmount());
157 void emitExpression(PadPrimOp op) { emitPrimExpr(
"pad", op, op.getAmount()); }
158 void emitExpression(ShlPrimOp op) { emitPrimExpr(
"shl", op, op.getAmount()); }
159 void emitExpression(ShrPrimOp op) { emitPrimExpr(
"shr", op, op.getAmount()); }
161 void emitExpression(TimeOp op){};
164#define HANDLE(OPTYPE, MNEMONIC) \
165 void emitExpression(OPTYPE op) { emitPrimExpr(MNEMONIC, op); }
180 HANDLE(DShlPrimOp,
"dshl");
181 HANDLE(DShlwPrimOp,
"dshlw");
182 HANDLE(DShrPrimOp,
"dshr");
184 HANDLE(AsSIntPrimOp,
"asSInt");
185 HANDLE(AsUIntPrimOp,
"asUInt");
186 HANDLE(AsAsyncResetPrimOp,
"asAsyncReset");
187 HANDLE(AsClockPrimOp,
"asClock");
191 HANDLE(AndRPrimOp,
"andr");
193 HANDLE(XorRPrimOp,
"xorr");
197 void emitAttribute(MemDirAttr attr);
198 void emitAttribute(RUWBehaviorAttr attr);
201 void emitType(Type type,
bool includeConst =
true);
202 void emitTypeWithColon(Type type) {
203 ps << PP::space <<
":" << PP::nbsp;
208 void emitDomains(Attribute domains,
209 const DenseMap<size_t, StringRef> &domainMap);
212 void emitLocation(Location loc);
213 void emitLocation(Operation *op) { emitLocation(op->getLoc()); }
214 template <
typename... Args>
215 void emitLocationAndNewLine(Args... args) {
218 ps << PP::neverbreak;
219 emitLocation(args...);
223 void emitAssignLike(llvm::function_ref<
void()> emitLHS,
224 llvm::function_ref<
void()> emitRHS,
226 std::optional<PPExtString> wordBeforeLHS = std::nullopt) {
228 ps.scopedBox(PP::ibox2, [&]() {
230 ps << *wordBeforeLHS << PP::space;
234 ps << PP::space << syntax << PP::nbsp;
236 ps.scopedBox(PP::ibox0, [&]() { emitRHS(); });
241 void emitSubExprIBox2(Value v) {
242 ps.scopedBox(PP::ibox2, [&]() { emitExpression(v); });
247 template <
typename Container,
typename EachFn>
248 void interleaveComma(
const Container &c, EachFn eachFn) {
249 llvm::interleave(c, eachFn, [&]() { ps <<
"," << PP::space; });
254 void interleaveComma(ValueRange ops) {
255 return interleaveComma(ops, [&](Value v) { emitSubExprIBox2(v); });
258 void emitStatementFunctionOp(
PPExtString name, Operation *op) {
261 ps.scopedBox(PP::ibox0, [&]() {
262 interleaveComma(op->getOperands());
265 emitLocationAndNewLine(op);
268 template <
typename EachFn,
typename Range>
269 void emitLiteralExpression(Type type,
const Range &r, EachFn eachFn) {
272 ps.scopedBox(PP::ibox0, [&]() {
273 interleaveComma(r, eachFn);
278 void emitLiteralExpression(Type type, ValueRange values) {
279 return emitLiteralExpression(type, values,
280 [&](Value v) { emitSubExprIBox2(v); });
284 void emitSymbol(SymbolRefAttr symbol) {
285 ps.ibox(2, IndentStyle::Block);
286 ps << symbol.getRootReference();
287 for (
auto nested : symbol.getNestedReferences()) {
290 ps << nested.getAttr();
297 InFlightDiagnostic emitError(Operation *op,
const Twine &message) {
298 encounteredError =
true;
299 return op->emitError(message);
303 InFlightDiagnostic emitOpError(Operation *op,
const Twine &message) {
304 encounteredError =
true;
305 return op->emitOpError(message);
310 std::optional<StringRef> lookupEmittedName(Value value) {
311 auto it = valueNames.find(value);
312 if (it != valueNames.end())
319 void emitPendingNewlineIfNeeded() {
320 if (pendingNewline) {
321 pendingNewline =
false;
325 void setPendingNewline() {
327 pendingNewline =
true;
330 void startStatement() { emitPendingNewlineIfNeeded(); }
348 bool pendingNewline =
false;
351 bool encounteredError =
false;
356 DenseMap<Value, StringRef> valueNames;
357 StringSet<> valueNamesStorage;
361 StringAttr legalize(StringAttr attr) {
362 StringRef str = attr.getValue();
363 if (str.empty() || !
isdigit(str.front()))
365 return StringAttr::get(attr.getContext(),
"`" + Twine(attr) +
"`");
368 void addValueName(Value value, StringAttr attr) {
369 valueNames.insert({value, attr.getValue()});
371 void addValueName(Value value, StringRef str) {
372 auto it = valueNamesStorage.insert(str);
373 valueNames.insert({value, it.first->getKey()});
375 void addForceable(Forceable op, StringAttr attr) {
376 addValueName(op.getData(), attr);
377 if (op.isForceable()) {
378 SmallString<32> rwName;
379 (Twine(
"rwprobe(") + attr.strref() +
")").
toVector(rwName);
380 addValueName(op.getDataRef(), rwName);
389 SymbolTable symbolTable;
392 SymInfos(Operation *op) : symbolTable(op), istc(op){};
394 std::optional<std::reference_wrapper<SymInfos>> symInfos;
401LogicalResult Emitter::finalize() {
return failure(encounteredError); }
404void Emitter::emitCircuit(CircuitOp op) {
405 circuitNamespace.add(op);
406 SymInfos circuitSymInfos(op);
407 symInfos = circuitSymInfos;
409 ps <<
"FIRRTL version ";
416 ps <<
"circuit " <<
PPExtString(legalize(op.getNameAttr())) <<
" :";
420 if (encounteredError)
422 TypeSwitch<Operation *>(&bodyOp)
423 .Case<FModuleOp, FExtModuleOp, FIntModuleOp>([&](
auto op) {
427 .Case<DomainOp, LayerOp, OptionOp, FormalOp, SimulationOp>(
428 [&](
auto op) { emitDeclaration(op); })
429 .Default([&](
auto op) {
430 emitOpError(op,
"not supported for emission inside circuit");
434 circuitNamespace.clear();
435 symInfos = std::nullopt;
438void Emitter::emitEnabledLayers(ArrayRef<Attribute> layers) {
439 for (
auto layer : layers) {
441 ps.
cbox(2, IndentStyle::Block);
442 ps <<
"enablelayer" << PP::space;
443 emitSymbol(cast<SymbolRefAttr>(layer));
448void Emitter::emitKnownLayers(ArrayRef<Attribute> layers) {
449 for (
auto layer : layers) {
451 ps.
cbox(2, IndentStyle::Block);
452 ps <<
"knownlayer" << PP::space;
453 emitSymbol(cast<SymbolRefAttr>(layer));
458void Emitter::emitParamAssign(ParamDeclAttr param, Operation *op,
459 std::optional<PPExtString> wordBeforeLHS) {
461 ps << *wordBeforeLHS << PP::nbsp;
463 ps <<
PPExtString(param.getName().strref()) << PP::nbsp <<
"=" << PP::nbsp;
464 emitParamValue(param.getValue(), op);
467void Emitter::emitParamValue(Attribute value, Operation *op) {
468 TypeSwitch<Attribute>(value)
469 .Case<IntegerAttr>([&](
auto attr) { ps.
addAsString(attr.getValue()); })
470 .Case<FloatAttr>([&](
auto attr) {
472 attr.getValue().toString(str);
477 .Case<ArrayAttr>([&](
auto attr) {
480 interleaveComma(attr.getValue(),
481 [&](
auto element) { emitParamValue(element, op); });
485 .Case<DictionaryAttr>([&](
auto attr) {
488 interleaveComma(attr.getValue(), [&](
auto field) {
489 ps << PPExtString(field.getName()) << PP::nbsp <<
"=" << PP::nbsp;
490 emitParamValue(field.getValue(), op);
495 .Default([&](
auto attr) {
496 emitOpError(op,
"with unsupported parameter attribute: ") << attr;
497 ps <<
"<unsupported-attr ";
503void Emitter::emitGenericIntrinsic(GenericIntrinsicOp op) {
507 ps << op.getIntrinsic();
509 auto params = op.getParameters();
510 if (!params.empty()) {
512 ps.scopedBox(PP::ibox0, [&]() {
514 params.getAsRange<ParamDeclAttr>(),
515 [&](ParamDeclAttr param) { emitParamAssign(param, op); });
520 if (op.getNumResults() != 0)
521 emitTypeWithColon(op.getResult().getType());
523 if (op.getNumOperands() != 0) {
524 ps <<
"," << PP::space;
525 ps.
scopedBox(PP::ibox0, [&]() { interleaveComma(op->getOperands()); });
532void Emitter::emitModule(FModuleOp op) {
534 ps.
cbox(4, IndentStyle::Block);
536 ps <<
"public" << PP::nbsp;
537 ps <<
"module " <<
PPExtString(legalize(op.getNameAttr()));
538 emitEnabledLayers(op.getLayers());
539 ps << PP::nbsp <<
":" << PP::end;
546 auto ports = op.getPorts();
547 emitModulePorts(ports, op.getArguments());
548 if (!ports.empty() && !op.getBodyBlock()->empty())
552 emitStatementsInBlock(*op.getBodyBlock());
555 valueNamesStorage.clear();
559void Emitter::emitModule(FExtModuleOp op) {
561 ps.
cbox(4, IndentStyle::Block);
562 ps <<
"extmodule " <<
PPExtString(legalize(op.getNameAttr()));
563 emitKnownLayers(op.getKnownLayers());
564 emitEnabledLayers(op.getLayers());
565 ps << PP::nbsp <<
":" << PP::end;
572 auto ports = op.getPorts();
573 emitModulePorts(ports);
576 if (op.getDefname() && !op.getDefname()->empty()) {
578 ps <<
"defname = " <<
PPExtString(*op.getDefname());
583 emitModuleParameters(op, op.getParameters());
588void Emitter::emitModule(FIntModuleOp op) {
590 ps.
cbox(4, IndentStyle::Block);
591 ps <<
"intmodule " <<
PPExtString(legalize(op.getNameAttr()));
592 emitEnabledLayers(op.getLayers());
593 ps << PP::nbsp <<
":" << PP::end;
600 auto ports = op.getPorts();
601 emitModulePorts(ports);
604 ps <<
"intrinsic = " <<
PPExtString(op.getIntrinsic());
608 emitModuleParameters(op, op.getParameters());
615void Emitter::emitModulePorts(ArrayRef<PortInfo> ports,
616 Block::BlockArgListType arguments) {
617 DenseMap<size_t, StringRef> domainMap;
618 for (
unsigned i = 0, e = ports.size(); i < e; ++i) {
620 const auto &port = ports[i];
621 ps << (port.direction == Direction::In ?
"input " :
"output ");
622 auto legalName = legalize(port.name);
623 if (isa<DomainType>(port.type))
624 domainMap.insert({i, port.name});
625 if (!arguments.empty())
626 addValueName(arguments[i], legalName);
629 emitDomains(port.domains, domainMap);
630 emitLocation(ports[i].loc);
635void Emitter::emitModuleParameters(Operation *op, ArrayAttr parameters) {
636 for (
auto param : parameters.getAsRange<ParamDeclAttr>()) {
638 emitParamAssign(param, op,
PPExtString(
"parameter"));
643void Emitter::emitDeclaration(DomainOp op) {
645 ps <<
"domain " <<
PPExtString(op.getSymName()) <<
" :";
646 emitLocationAndNewLine(op);
650void Emitter::emitDeclaration(LayerOp op) {
652 ps <<
"layer " <<
PPExtString(op.getSymName()) <<
", "
653 <<
PPExtString(stringifyLayerConvention(op.getConvention()));
655 if (
auto outputFile = op->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
661 emitLocationAndNewLine(op);
663 for (
auto &bodyOp : op.getBody().getOps()) {
664 TypeSwitch<Operation *>(&bodyOp)
665 .Case<LayerOp>([&](
auto op) { emitDeclaration(op); })
666 .Default([&](
auto op) {
668 "not supported for emission inside layer definition");
675void Emitter::emitDeclaration(OptionOp op) {
677 ps <<
"option " <<
PPExtString(legalize(op.getSymNameAttr())) <<
" :";
680 for (
auto caseOp : op.getBody().getOps<OptionCaseOp>()) {
682 ps <<
PPExtString(legalize(caseOp.getSymNameAttr()));
683 emitLocation(caseOp);
686 ps << PP::newline << PP::newline;
690void Emitter::emitDeclaration(FormalOp op) {
691 emitFormalLike(op,
"formal", op.getSymNameAttr(),
692 op.getModuleNameAttr().getAttr(), op.getParameters());
696void Emitter::emitDeclaration(SimulationOp op) {
697 emitFormalLike(op,
"simulation", op.getSymNameAttr(),
698 op.getModuleNameAttr().getAttr(), op.getParameters());
702void Emitter::emitFormalLike(Operation *op, StringRef keyword,
703 StringAttr symName, StringAttr moduleName,
704 DictionaryAttr params) {
706 ps.
cbox(4, IndentStyle::Block);
707 ps << keyword <<
" " <<
PPExtString(legalize(symName));
709 ps << PP::nbsp <<
":" << PP::end;
714 for (
auto param : params) {
716 ps <<
PPExtString(param.getName()) << PP::nbsp <<
"=" << PP::nbsp;
717 emitParamValue(param.getValue(), op);
731 return (
isExpression(op) && !isa<InvalidValueOp>(op)) ||
732 (isa<GenericIntrinsicOp>(op) && op->hasOneUse() &&
736void Emitter::emitStatementsInBlock(Block &block) {
737 for (
auto &bodyOp : block) {
738 if (encounteredError)
742 TypeSwitch<Operation *>(&bodyOp)
743 .Case<WhenOp, WireOp, RegOp, RegResetOp, NodeOp, StopOp, SkipOp,
744 PrintFOp, FPrintFOp, FFlushOp, AssertOp, AssumeOp, CoverOp,
745 ConnectOp, MatchingConnectOp, PropAssignOp, InstanceOp,
746 InstanceChoiceOp, AttachOp, MemOp, InvalidValueOp, SeqMemOp,
747 CombMemOp, MemoryPortOp, MemoryDebugPortOp, MemoryPortAccessOp,
748 RefDefineOp, RefForceOp, RefForceInitialOp, RefReleaseOp,
749 RefReleaseInitialOp, LayerBlockOp, GenericIntrinsicOp>(
750 [&](
auto op) { emitStatement(op); })
751 .Default([&](
auto op) {
753 ps <<
"// operation " <<
PPExtString(op->getName().getStringRef());
755 emitOpError(op,
"not supported as statement");
760void Emitter::emitStatement(WhenOp op) {
763 emitExpression(op.getCondition());
765 emitLocationAndNewLine(op);
766 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(op.getThenBlock()); });
768 if (!op.hasElseRegion())
775 auto &elseBlock = op.getElseBlock();
776 if (!elseBlock.empty() && &elseBlock.front() == &elseBlock.back()) {
777 if (
auto whenOp = dyn_cast<WhenOp>(&elseBlock.front())) {
778 emitStatement(whenOp);
785 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(elseBlock); });
788void Emitter::emitStatement(WireOp op) {
789 auto legalName = legalize(op.getNameAttr());
790 addForceable(op, legalName);
794 emitTypeWithColon(op.getResult().getType());
796 emitLocationAndNewLine(op);
799void Emitter::emitStatement(RegOp op) {
800 auto legalName = legalize(op.getNameAttr());
801 addForceable(op, legalName);
805 emitTypeWithColon(op.getResult().getType());
806 ps <<
"," << PP::space;
807 emitExpression(op.getClockVal());
809 emitLocationAndNewLine(op);
812void Emitter::emitStatement(RegResetOp op) {
813 auto legalName = legalize(op.getNameAttr());
814 addForceable(op, legalName);
818 ps <<
"regreset " << legalName;
819 emitTypeWithColon(op.getResult().getType());
820 ps <<
"," << PP::space;
821 emitExpression(op.getClockVal());
822 ps <<
"," << PP::space;
823 emitExpression(op.getResetSignal());
824 ps <<
"," << PP::space;
825 emitExpression(op.getResetValue());
829 ps <<
"reg " << legalName;
830 emitTypeWithColon(op.getResult().getType());
831 ps <<
"," << PP::space;
832 emitExpression(op.getClockVal());
833 ps << PP::space <<
"with :";
835 ps << PP::neverbreak;
838 ps <<
"reset => (" << PP::ibox0;
839 emitExpression(op.getResetSignal());
840 ps <<
"," << PP::space;
841 emitExpression(op.getResetValue());
842 ps <<
")" << PP::end;
845 emitLocationAndNewLine(op);
848void Emitter::emitStatement(NodeOp op) {
849 auto legalName = legalize(op.getNameAttr());
850 addForceable(op, legalName);
852 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(legalName); },
853 [&]() { emitExpression(op.getInput()); });
854 emitLocationAndNewLine(op);
857void Emitter::emitStatement(StopOp op) {
860 ps <<
"stop(" << PP::ibox0;
861 emitExpression(op.getClock());
862 ps <<
"," << PP::space;
863 emitExpression(op.getCond());
864 ps <<
"," << PP::space;
866 ps <<
")" << PP::end;
867 if (!op.getName().empty()) {
868 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
871 emitLocationAndNewLine(op);
874void Emitter::emitStatement(SkipOp op) {
877 emitLocationAndNewLine(op);
880void Emitter::emitFormatString(Operation *op, StringRef origFormatString,
881 OperandRange substitutionOperands,
882 llvm::SmallVectorImpl<Value> &substitutions) {
891 SmallString<64> formatString;
892 for (
size_t i = 0, e = origFormatString.size(), opIdx = 0; i != e; ++i) {
893 auto c = origFormatString[i];
896 formatString.push_back(c);
899 SmallString<6> width;
900 c = origFormatString[++i];
903 c = origFormatString[++i];
912 formatString.append(width);
915 substitutions.push_back(substitutionOperands[opIdx++]);
918 formatString.push_back(c);
923 if (origFormatString.slice(i, i + 4) ==
"{{}}") {
924 formatString.append(
"{{");
925 TypeSwitch<Operation *>(substitutionOperands[opIdx++].getDefiningOp())
927 [&](
auto time) { formatString.append(
"SimulationTime"); })
928 .Case<HierarchicalModuleNameOp>([&](
auto time) {
929 formatString.append(
"HierarchicalModuleName");
932 emitError(op,
"unsupported fstring substitution type");
934 formatString.append(
"}}");
939 formatString.push_back(c);
945void Emitter::emitStatement(PrintFOp op) {
948 ps <<
"printf(" << PP::ibox0;
949 emitExpression(op.getClock());
950 ps <<
"," << PP::space;
951 emitExpression(op.getCond());
952 ps <<
"," << PP::space;
954 SmallVector<Value, 4> substitutions;
955 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
957 for (
auto operand : substitutions) {
958 ps <<
"," << PP::space;
959 emitExpression(operand);
961 ps <<
")" << PP::end;
962 if (!op.getName().empty()) {
963 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
966 emitLocationAndNewLine(op);
969void Emitter::emitStatement(FPrintFOp op) {
972 ps <<
"fprintf(" << PP::ibox0;
973 emitExpression(op.getClock());
974 ps <<
"," << PP::space;
975 emitExpression(op.getCond());
976 ps <<
"," << PP::space;
978 SmallVector<Value, 4> outputFileSubstitutions;
979 emitFormatString(op, op.getOutputFile(), op.getOutputFileSubstitutions(),
980 outputFileSubstitutions);
981 if (!outputFileSubstitutions.empty()) {
982 ps <<
"," << PP::space;
983 interleaveComma(outputFileSubstitutions);
986 ps <<
"," << PP::space;
987 SmallVector<Value, 4> substitutions;
988 emitFormatString(op, op.getFormatString(), op.getSubstitutions(),
990 if (!substitutions.empty()) {
991 ps <<
"," << PP::space;
992 interleaveComma(substitutions);
995 ps <<
")" << PP::end;
996 if (!op.getName().empty()) {
997 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1000 emitLocationAndNewLine(op);
1003void Emitter::emitStatement(FFlushOp op) {
1006 ps <<
"fflush(" << PP::ibox0;
1007 emitExpression(op.getClock());
1008 ps <<
"," << PP::space;
1009 emitExpression(op.getCond());
1010 if (op.getOutputFileAttr()) {
1011 ps <<
"," << PP::space;
1012 SmallVector<Value, 4> substitutions;
1013 emitFormatString(op, op.getOutputFileAttr(),
1014 op.getOutputFileSubstitutions(), substitutions);
1015 if (!substitutions.empty()) {
1016 ps <<
"," << PP::space;
1017 interleaveComma(substitutions);
1020 ps <<
")" << PP::end;
1022 emitLocationAndNewLine(op);
1026void Emitter::emitVerifStatement(T op, StringRef mnemonic) {
1029 ps << mnemonic <<
"(" << PP::ibox0;
1030 emitExpression(op.getClock());
1031 ps <<
"," << PP::space;
1032 emitExpression(op.getPredicate());
1033 ps <<
"," << PP::space;
1034 emitExpression(op.getEnable());
1035 ps <<
"," << PP::space;
1037 ps <<
")" << PP::end;
1038 if (!op.getName().empty()) {
1039 ps << PP::space <<
": " <<
PPExtString(legalize(op.getNameAttr()));
1042 emitLocationAndNewLine(op);
1045void Emitter::emitStatement(ConnectOp op) {
1049 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1050 ps <<
"invalidate" << PP::space;
1051 emitExpression(op.getDest());
1053 ps <<
"connect" << PP::space;
1054 emitExpression(op.getDest());
1055 ps <<
"," << PP::space;
1056 emitExpression(op.getSrc());
1060 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1061 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1063 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1066 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1069 emitLocationAndNewLine(op);
1072void Emitter::emitStatement(MatchingConnectOp op) {
1076 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1077 ps <<
"invalidate" << PP::space;
1078 emitExpression(op.getDest());
1080 ps <<
"connect" << PP::space;
1081 emitExpression(op.getDest());
1082 ps <<
"," << PP::space;
1083 emitExpression(op.getSrc());
1087 auto emitLHS = [&]() { emitExpression(op.getDest()); };
1088 if (op.getSrc().getDefiningOp<InvalidValueOp>()) {
1090 emitLHS, [&]() { ps <<
"invalid"; },
PPExtString(
"is"));
1093 emitLHS, [&]() { emitExpression(op.getSrc()); },
PPExtString(
"<="));
1096 emitLocationAndNewLine(op);
1099void Emitter::emitStatement(PropAssignOp op) {
1102 ps <<
"propassign" << PP::space;
1103 interleaveComma(op.getOperands());
1105 emitLocationAndNewLine(op);
1108void Emitter::emitStatement(InstanceOp op) {
1110 auto legalName = legalize(op.getNameAttr());
1112 <<
PPExtString(legalize(op.getModuleNameAttr().getAttr()));
1113 emitLocationAndNewLine(op);
1117 SmallString<16> portName(legalName);
1118 portName.push_back(
'.');
1119 unsigned baseLen = portName.size();
1120 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1121 portName.append(legalize(op.getPortName(i)));
1122 addValueName(op.getResult(i), portName);
1123 portName.resize(baseLen);
1127void Emitter::emitStatement(InstanceChoiceOp op) {
1129 auto legalName = legalize(op.getNameAttr());
1130 ps <<
"instchoice " <<
PPExtString(legalName) <<
" of "
1131 <<
PPExtString(legalize(op.getDefaultTargetAttr().getAttr())) <<
", "
1132 <<
PPExtString(legalize(op.getOptionNameAttr())) <<
" :";
1135 for (
const auto &[optSym, targetSym] : op.getTargetChoices()) {
1137 ps <<
PPExtString(legalize(optSym.getLeafReference()));
1142 setPendingNewline();
1144 SmallString<16> portName(legalName);
1145 portName.push_back(
'.');
1146 unsigned baseLen = portName.size();
1147 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i) {
1148 portName.append(legalize(op.getPortName(i)));
1149 addValueName(op.getResult(i), portName);
1150 portName.resize(baseLen);
1154void Emitter::emitStatement(AttachOp op) {
1155 emitStatementFunctionOp(
PPExtString(
"attach"), op);
1158void Emitter::emitStatement(MemOp op) {
1159 auto legalName = legalize(op.getNameAttr());
1160 SmallString<16> portName(legalName);
1161 portName.push_back(
'.');
1162 auto portNameBaseLen = portName.size();
1163 for (
auto result :
llvm::zip(op.getResults(), op.getPortNames())) {
1164 portName.resize(portNameBaseLen);
1165 portName.append(legalize(cast<StringAttr>(std::get<1>(result))));
1166 addValueName(std::get<0>(result), portName);
1171 emitLocationAndNewLine(op);
1174 ps <<
"data-type => ";
1175 emitType(op.getDataType());
1180 ps <<
"read-latency => ";
1183 ps <<
"write-latency => ";
1187 SmallString<16> reader, writer, readwriter;
1188 for (std::pair<StringAttr, MemOp::PortKind> port : op.getPorts()) {
1189 auto add = [&](SmallString<16> &to, StringAttr name) {
1192 to.append(name.getValue());
1194 switch (port.second) {
1195 case MemOp::PortKind::Read:
1196 add(reader, legalize(port.first));
1198 case MemOp::PortKind::Write:
1199 add(writer, legalize(port.first));
1201 case MemOp::PortKind::ReadWrite:
1202 add(readwriter, legalize(port.first));
1204 case MemOp::PortKind::Debug:
1205 emitOpError(op,
"has unsupported 'debug' port");
1209 if (!reader.empty())
1210 ps <<
"reader => " << reader << PP::newline;
1211 if (!writer.empty())
1212 ps <<
"writer => " << writer << PP::newline;
1213 if (!readwriter.empty())
1214 ps <<
"readwriter => " << readwriter << PP::newline;
1216 ps <<
"read-under-write => ";
1217 emitAttribute(op.getRuwAttr());
1218 setPendingNewline();
1222void Emitter::emitStatement(SeqMemOp op) {
1225 ps <<
"smem " <<
PPExtString(legalize(op.getNameAttr()));
1226 emitTypeWithColon(op.getType());
1227 ps <<
"," << PP::space;
1228 emitAttribute(op.getRuwAttr());
1230 emitLocationAndNewLine(op);
1233void Emitter::emitStatement(CombMemOp op) {
1236 ps <<
"cmem " <<
PPExtString(legalize(op.getNameAttr()));
1237 emitTypeWithColon(op.getType());
1239 emitLocationAndNewLine(op);
1242void Emitter::emitStatement(MemoryPortOp op) {
1244 addValueName(op.getData(), legalize(op.getNameAttr()));
1247void Emitter::emitStatement(MemoryDebugPortOp op) {
1249 addValueName(op.getData(), legalize(op.getNameAttr()));
1252void Emitter::emitStatement(MemoryPortAccessOp op) {
1256 auto port = cast<MemoryPortOp>(op.getPort().getDefiningOp());
1257 emitAttribute(port.getDirection());
1259 ps <<
" mport " <<
PPExtString(legalize(port.getNameAttr())) <<
" = ";
1262 auto *mem = port.getMemory().getDefiningOp();
1263 if (
auto seqMem = dyn_cast<SeqMemOp>(mem))
1264 ps << legalize(seqMem.getNameAttr());
1266 ps << legalize(cast<CombMemOp>(mem).getNameAttr());
1270 emitExpression(op.getIndex());
1274 emitExpression(op.getClock());
1276 emitLocationAndNewLine(op);
1279void Emitter::emitStatement(RefDefineOp op) {
1281 emitAssignLike([&]() { emitExpression(op.getDest()); },
1282 [&]() { emitExpression(op.getSrc()); },
PPExtString(
"="),
1284 emitLocationAndNewLine(op);
1287void Emitter::emitStatement(RefForceOp op) {
1288 emitStatementFunctionOp(
PPExtString(
"force"), op);
1291void Emitter::emitStatement(RefForceInitialOp op) {
1293 auto constantPredicate =
1294 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1295 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1298 emitExpression(op.getPredicate());
1299 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1301 ps <<
"force_initial(";
1303 interleaveComma({op.getDest(), op.getSrc()});
1308 emitLocationAndNewLine(op);
1311void Emitter::emitStatement(RefReleaseOp op) {
1312 emitStatementFunctionOp(
PPExtString(
"release"), op);
1315void Emitter::emitStatement(RefReleaseInitialOp op) {
1317 auto constantPredicate =
1318 dyn_cast_or_null<ConstantOp>(op.getPredicate().getDefiningOp());
1319 bool hasEnable = !constantPredicate || constantPredicate.getValue() == 0;
1322 emitExpression(op.getPredicate());
1323 ps <<
":" << PP::bbox2 << PP::neverbreak << PP::newline;
1325 ps <<
"release_initial(";
1326 emitExpression(op.getDest());
1330 emitLocationAndNewLine(op);
1333void Emitter::emitStatement(LayerBlockOp op) {
1335 ps <<
"layerblock " << op.getLayerName().getLeafReference() <<
" :";
1336 emitLocationAndNewLine(op);
1337 auto *body = op.getBody();
1338 ps.
scopedBox(PP::bbox2, [&]() { emitStatementsInBlock(*body); });
1341void Emitter::emitStatement(InvalidValueOp op) {
1344 if (llvm::all_of(op->getUses(), [&](OpOperand &use) {
1345 return use.getOperandNumber() == 1 &&
1346 isa<ConnectOp, MatchingConnectOp>(use.getOwner());
1352 auto name = circuitNamespace.newName(
"_invalid");
1353 addValueName(op, name);
1355 emitType(op.getType());
1356 emitLocationAndNewLine(op);
1362 emitLocationAndNewLine(op);
1365void Emitter::emitStatement(GenericIntrinsicOp op) {
1368 emitGenericIntrinsic(op);
1371 auto name = circuitNamespace.newName(
"_gen_int");
1372 addValueName(op.getResult(), name);
1373 emitAssignLike([&]() { ps <<
"node " <<
PPExtString(name); },
1374 [&]() { emitGenericIntrinsic(op); });
1376 emitLocationAndNewLine(op);
1379void Emitter::emitExpression(Value value) {
1382 if (
auto name = lookupEmittedName(value)) {
1388 auto op = value.getDefiningOp();
1389 assert(op &&
"value must either be a block arg or the result of an op");
1390 TypeSwitch<Operation *>(op)
1393 ConstantOp, SpecialConstantOp, SubfieldOp, SubindexOp, SubaccessOp,
1394 OpenSubfieldOp, OpenSubindexOp,
1396 AddPrimOp, SubPrimOp, MulPrimOp, DivPrimOp, RemPrimOp, AndPrimOp,
1397 OrPrimOp, XorPrimOp, LEQPrimOp, LTPrimOp, GEQPrimOp, GTPrimOp,
1398 EQPrimOp, NEQPrimOp, DShlPrimOp, DShlwPrimOp, DShrPrimOp,
1400 AsSIntPrimOp, AsUIntPrimOp, AsAsyncResetPrimOp, AsClockPrimOp,
1401 CvtPrimOp, NegPrimOp, NotPrimOp, AndRPrimOp, OrRPrimOp, XorRPrimOp,
1403 BitsPrimOp, HeadPrimOp, TailPrimOp, PadPrimOp, MuxPrimOp, ShlPrimOp,
1404 ShrPrimOp, UninferredResetCastOp, ConstCastOp, StringConstantOp,
1405 FIntegerConstantOp, BoolConstantOp, DoubleConstantOp, ListCreateOp,
1406 UnresolvedPathOp, GenericIntrinsicOp, CatPrimOp, UnsafeDomainCastOp,
1408 RefSendOp, RefResolveOp, RefSubOp, RWProbeOp, RefCastOp,
1410 TimeOp>([&](
auto op) {
1411 ps.
scopedBox(PP::ibox0, [&]() { emitExpression(op); });
1413 .Default([&](
auto op) {
1414 emitOpError(op,
"not supported as expression");
1415 ps <<
"<unsupported-expr-" <<
PPExtString(op->getName().stripDialect())
1420void Emitter::emitExpression(ConstantOp op) {
1422 emitType(op.getType(),
false);
1429void Emitter::emitExpression(SpecialConstantOp op) {
1430 auto emitInner = [&]() {
1437 .
Case<ClockType>([&](
auto type) {
1442 .Case<ResetType>([&](
auto type) { emitInner(); })
1443 .Case<AsyncResetType>([&](
auto type) {
1444 ps <<
"asAsyncReset(";
1451void Emitter::emitExpression(SubfieldOp op) {
1452 BundleType type = op.getInput().getType();
1453 emitExpression(op.getInput());
1454 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1458void Emitter::emitExpression(SubindexOp op) {
1459 emitExpression(op.getInput());
1466void Emitter::emitExpression(SubaccessOp op) {
1467 emitExpression(op.getInput());
1469 emitExpression(op.getIndex());
1473void Emitter::emitExpression(OpenSubfieldOp op) {
1474 auto type = op.getInput().getType();
1475 emitExpression(op.getInput());
1476 ps <<
"." << legalize(type.getElementNameAttr(op.getFieldIndex()));
1479void Emitter::emitExpression(OpenSubindexOp op) {
1480 emitExpression(op.getInput());
1486void Emitter::emitExpression(RefSendOp op) {
1488 emitExpression(op.getBase());
1492void Emitter::emitExpression(RefResolveOp op) {
1494 emitExpression(op.getRef());
1498void Emitter::emitExpression(RefSubOp op) {
1499 emitExpression(op.getInput());
1501 .
Case<FVectorType>([&](
auto type) {
1507 [&](
auto type) { ps <<
"." << type.getElementName(op.getIndex()); });
1510void Emitter::emitExpression(RWProbeOp op) {
1514 auto target = symInfos->get().irn.lookup(op.getTarget());
1516 if (target.isPort()) {
1517 auto mod = cast<FModuleOp>(target.getOp());
1518 auto port = target.getPort();
1519 base = mod.getArgument(port);
1521 base = cast<hw::InnerSymbolOpInterface>(target.getOp()).getTargetResult();
1524 emitExpression(base);
1527 auto fieldID = target.getField();
1528 auto type = base.getType();
1531 .
Case<FVectorType, OpenVectorType>([&](
auto vecTy) {
1532 auto index = vecTy.getIndexForFieldID(fieldID);
1536 auto [subtype, subfieldID] = vecTy.getSubTypeByFieldID(fieldID);
1538 fieldID = subfieldID;
1540 .Case<BundleType, OpenBundleType>([&](
auto bundleTy) {
1541 auto index = bundleTy.getIndexForFieldID(fieldID);
1542 ps <<
"." << bundleTy.getElementName(index);
1543 auto [subtype, subfieldID] = bundleTy.getSubTypeByFieldID(fieldID);
1545 fieldID = subfieldID;
1551void Emitter::emitExpression(RefCastOp op) { emitExpression(op.getInput()); }
1553void Emitter::emitExpression(UninferredResetCastOp op) {
1554 emitExpression(op.getInput());
1557void Emitter::emitExpression(FIntegerConstantOp op) {
1563void Emitter::emitExpression(BoolConstantOp op) {
1564 ps <<
"Bool(" << (op.getValue() ?
"true" :
"false") <<
")";
1567void Emitter::emitExpression(DoubleConstantOp op) {
1573 SmallString<16> str;
1574 op.getValueAttr().getValue().toString(str);
1579void Emitter::emitExpression(StringConstantOp op) {
1585void Emitter::emitExpression(ListCreateOp op) {
1586 return emitLiteralExpression(op.getType(), op.getElements());
1589void Emitter::emitExpression(UnresolvedPathOp op) {
1595void Emitter::emitExpression(GenericIntrinsicOp op) {
1596 emitGenericIntrinsic(op);
1599void Emitter::emitExpression(ConstCastOp op) { emitExpression(op.getInput()); }
1601void Emitter::emitPrimExpr(StringRef mnemonic, Operation *op,
1602 ArrayRef<uint32_t> attrs) {
1603 ps << mnemonic <<
"(" << PP::ibox0;
1604 interleaveComma(op->getOperands());
1605 if (!op->getOperands().empty() && !attrs.empty())
1606 ps <<
"," << PP::space;
1607 interleaveComma(attrs, [&](
auto attr) { ps.
addAsString(attr); });
1608 ps <<
")" << PP::end;
1611void Emitter::emitExpression(CatPrimOp op) {
1612 size_t numOperands = op.getNumOperands();
1613 switch (numOperands) {
1616 emitType(op.getType(),
false);
1620 auto operand = op->getOperand(0);
1622 if (isa<UIntType>(operand.getType()))
1623 return emitExpression(operand);
1626 ps <<
"cat(" << PP::ibox0;
1627 emitExpression(op->getOperand(0));
1628 ps <<
"," << PP::space <<
"SInt<0>(0))" << PP::end;
1634 for (
size_t i = 0; i < numOperands - 1; ++i) {
1635 ps <<
"cat(" << PP::ibox0;
1636 emitExpression(op->getOperand(i));
1637 ps <<
"," << PP::space;
1640 emitExpression(op->getOperand(numOperands - 1));
1641 for (
size_t i = 0; i < numOperands - 1; ++i)
1642 ps <<
")" << PP::end;
1647void Emitter::emitExpression(UnsafeDomainCastOp op) {
1648 ps <<
"unsafe_domain_cast(" << PP::ibox0;
1649 interleaveComma(op.getOperands(),
1650 [&](Value operand) { emitExpression(operand); });
1651 ps <<
")" << PP::end;
1654void Emitter::emitAttribute(MemDirAttr attr) {
1656 case MemDirAttr::Infer:
1659 case MemDirAttr::Read:
1662 case MemDirAttr::Write:
1665 case MemDirAttr::ReadWrite:
1671void Emitter::emitAttribute(RUWBehaviorAttr attr) {
1672 switch (attr.getValue()) {
1673 case RUWBehavior::Undefined:
1676 case RUWBehavior::Old:
1679 case RUWBehavior::New:
1686void Emitter::emitType(Type type,
bool includeConst) {
1687 if (includeConst &&
isConst(type))
1689 auto emitWidth = [&](std::optional<int32_t> width) {
1698 .
Case<ClockType>([&](
auto) { ps <<
"Clock"; })
1699 .Case<ResetType>([&](
auto) { ps <<
"Reset"; })
1700 .Case<AsyncResetType>([&](
auto) { ps <<
"AsyncReset"; })
1701 .Case<UIntType>([&](
auto type) {
1703 emitWidth(type.getWidth());
1705 .Case<SIntType>([&](
auto type) {
1707 emitWidth(type.getWidth());
1709 .Case<AnalogType>([&](
auto type) {
1711 emitWidth(type.getWidth());
1713 .Case<OpenBundleType, BundleType>([&](
auto type) {
1715 if (!type.getElements().empty())
1717 bool anyEmitted =
false;
1719 for (
auto &element : type.getElements()) {
1721 ps <<
"," << PP::space;
1725 ps << legalize(element.name);
1726 emitTypeWithColon(element.type);
1735 .Case<OpenVectorType, FVectorType, CMemoryType>([&](
auto type) {
1736 emitType(type.getElementType());
1741 .Case<RefType>([&](RefType type) {
1742 if (type.getForceable())
1745 ps.
cbox(2, IndentStyle::Block);
1747 emitType(type.getType());
1748 if (
auto layer = type.getLayer()) {
1751 emitSymbol(type.getLayer());
1756 .Case<AnyRefType>([&](AnyRefType type) { ps <<
"AnyRef"; })
1757 .Case<StringType>([&](StringType type) { ps <<
"String"; })
1758 .Case<FIntegerType>([&](FIntegerType type) { ps <<
"Integer"; })
1759 .Case<BoolType>([&](BoolType type) { ps <<
"Bool"; })
1760 .Case<DoubleType>([&](DoubleType type) { ps <<
"Double"; })
1761 .Case<PathType>([&](PathType type) { ps <<
"Path"; })
1762 .Case<ListType>([&](ListType type) {
1764 emitType(type.getElementType());
1767 .Case<DomainType>([&](DomainType type) { ps <<
"Domain"; })
1768 .Default([&](
auto type) {
1769 llvm_unreachable(
"all types should be implemented");
1773void Emitter::emitDomains(Attribute attr,
1774 const DenseMap<size_t, StringRef> &domainMap) {
1777 if (
auto domains = dyn_cast<ArrayAttr>(attr)) {
1778 if (domains.empty())
1782 interleaveComma(domains, [&](Attribute attr) {
1783 auto itr = domainMap.find(cast<IntegerAttr>(attr).getUInt());
1784 assert(itr != domainMap.end() &&
"Unable to find domain");
1790 auto kind = cast<FlatSymbolRefAttr>(attr);
1797void Emitter::emitLocation(Location loc) {
1799 ps << PP::neverbreak;
1801 dyn_cast_or_null<FileLineColLoc, LocationAttr>(LocationAttr(loc))) {
1802 ps <<
" @[" << fileLoc.getFilename().getValue();
1803 if (
auto line = fileLoc.getLine()) {
1806 if (
auto col = fileLoc.getColumn()) {
1823 std::optional<size_t> targetLineLength,
1825 Emitter emitter(os, version,
1826 targetLineLength.value_or(defaultTargetLineLength));
1827 for (
auto &op : *
module.getBody()) {
1828 if (auto circuitOp = dyn_cast<CircuitOp>(op))
1829 emitter.emitCircuit(circuitOp);
1831 return emitter.finalize();
1836 "target-line-length",
1837 llvm::cl::desc(
"Target line length for emitted .fir"),
1838 llvm::cl::value_desc(
"number of chars"),
1839 llvm::cl::init(defaultTargetLineLength));
1840 static mlir::TranslateFromMLIRRegistration toFIR(
1841 "export-firrtl",
"emit FIRRTL dialect operations to .fir output",
1842 [](ModuleOp module, llvm::raw_ostream &os) {
1845 [](mlir::DialectRegistry ®istry) {
1846 registry.insert<chirrtl::CHIRRTLDialect>();
1847 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.