17 #include "mlir/IR/ImplicitLocOpBuilder.h"
18 #include "llvm/ADT/APSInt.h"
19 #include "llvm/ADT/SmallSet.h"
20 #include "llvm/Support/Debug.h"
22 #define DEBUG_TYPE "firrtl-reductions"
25 using namespace circt;
36 return tables.getSymbolTable(op);
39 return getSymbolTable(SymbolTable::getNearestSymbolTable(op));
43 auto it = userMaps.find(op);
44 if (it != userMaps.end())
46 return userMaps.insert({op, SymbolUserMap(tables, op)}).first->second;
49 return getSymbolUserMap(SymbolTable::getNearestSymbolTable(op));
53 tables = SymbolTableCollection();
65 static std::optional<firrtl::FModuleOp>
68 auto *tableOp = SymbolTable::getNearestSymbolTable(instOp);
69 auto moduleOp = dyn_cast<firrtl::FModuleOp>(
71 return moduleOp ? std::optional(moduleOp) : std::nullopt;
76 void clear() { moduleSizes.clear(); }
79 if (
auto it = moduleSizes.find(module); it != moduleSizes.end())
82 module->walk([&](Operation *op) {
84 if (
auto instOp = dyn_cast<firrtl::InstanceOp>(op))
86 size += getModuleSize(*instModule, symbols);
88 moduleSizes.insert({module, size});
98 return llvm::all_of(arg.getUses(), [](OpOperand &use) {
99 auto *op = use.getOwner();
100 if (!isa<firrtl::ConnectOp, firrtl::MatchingConnectOp>(op))
102 if (use.getOperandNumber() != 0)
104 if (!op->getOperand(1).getDefiningOp<firrtl::InvalidValueOp>())
116 void clear() { nlasToRemove.clear(); }
121 unsigned numRemoved = 0;
123 for (Operation &rootOp : *module.getBody()) {
124 if (!isa<firrtl::CircuitOp>(&rootOp))
126 SymbolTable symbolTable(&rootOp);
127 for (
auto sym : nlasToRemove) {
128 if (
auto *op = symbolTable.lookup(sym)) {
135 unsigned numLost = nlasToRemove.size() - numRemoved;
136 if (numRemoved > 0 || numLost > 0) {
137 llvm::dbgs() <<
"Removed " << numRemoved <<
" NLAs";
139 llvm::dbgs() <<
" (" << numLost <<
" no longer there)";
140 llvm::dbgs() <<
"\n";
149 if (
auto dict = dyn_cast<DictionaryAttr>(anno)) {
150 if (
auto field = dict.getAs<FlatSymbolRefAttr>(
"circt.nonlocal"))
151 nlasToRemove.insert(field.getAttr());
152 for (
auto namedAttr : dict)
153 markNLAsInAnnotation(namedAttr.getValue());
154 }
else if (
auto array = dyn_cast<ArrayAttr>(anno)) {
155 for (
auto attr : array)
156 markNLAsInAnnotation(attr);
164 op->walk([&](Operation *op) {
165 if (
auto annos = op->getAttrOfType<ArrayAttr>(
"annotations"))
166 markNLAsInAnnotation(annos);
187 uint64_t
match(firrtl::FModuleOp module)
override {
188 return moduleSizes.getModuleSize(module, symbols);
191 LogicalResult
rewrite(firrtl::FModuleOp module)
override {
192 nlaRemover.markNLAsInOperation(module);
193 OpBuilder builder(module);
194 builder.create<firrtl::FExtModuleOp>(
196 module->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName()),
197 module.getConventionAttr(), module.getPorts(), StringRef(),
198 module.getAnnotationsAttr());
203 std::string
getName()
const override {
return "firrtl-module-externalizer"; }
217 auto type = dyn_cast<firrtl::FIRRTLType>(value.getType());
222 if (
auto bundleType = dyn_cast<firrtl::BundleType>(type)) {
223 for (
auto element : llvm::enumerate(bundleType.getElements())) {
225 builder.createOrFold<firrtl::SubfieldOp>(value, element.index());
227 flip ^ element.value().isFlip);
228 if (subfield.use_empty())
229 subfield.getDefiningOp()->erase();
235 if (
auto vectorType = dyn_cast<firrtl::FVectorType>(type)) {
236 for (
unsigned i = 0, e = vectorType.getNumElements(); i != e; ++i) {
237 auto subindex = builder.createOrFold<firrtl::SubindexOp>(value, i);
239 if (subindex.use_empty())
240 subindex.getDefiningOp()->erase();
248 Value invalid = invalidCache.lookup(type);
250 invalid = builder.create<firrtl::InvalidValueOp>(type);
251 invalidCache.insert({type, invalid});
253 builder.create<firrtl::ConnectOp>(value, invalid);
259 auto type = dyn_cast<firrtl::FIRRTLBaseType>(dest.getType());
262 if (
auto bundleType = dyn_cast<firrtl::BundleType>(type)) {
263 for (
auto element : llvm::enumerate(bundleType.getElements()))
265 builder.create<firrtl::SubfieldOp>(dest, element.index()),
269 if (
auto vectorType = dyn_cast<firrtl::FVectorType>(type)) {
270 for (
unsigned i = 0, e = vectorType.getNumElements(); i != e; ++i)
271 connectToLeafs(builder, builder.create<firrtl::SubindexOp>(dest, i),
275 auto valueType = dyn_cast<firrtl::FIRRTLBaseType>(value.getType());
278 auto destWidth = type.getBitWidthOrSentinel();
279 auto valueWidth = valueType ? valueType.getBitWidthOrSentinel() : -1;
280 if (destWidth >= 0 && valueWidth >= 0 && destWidth < valueWidth)
281 value = builder.create<firrtl::HeadPrimOp>(value, destWidth);
282 if (!isa<firrtl::UIntType>(type)) {
283 if (isa<firrtl::SIntType>(type))
284 value = builder.create<firrtl::AsSIntPrimOp>(value);
288 builder.create<firrtl::ConnectOp>(dest, value);
292 static void reduceXor(ImplicitLocOpBuilder &builder, Value &into, Value value) {
293 auto type = dyn_cast<firrtl::FIRRTLType>(value.getType());
296 if (
auto bundleType = dyn_cast<firrtl::BundleType>(type)) {
297 for (
auto element : llvm::enumerate(bundleType.getElements()))
300 builder.createOrFold<firrtl::SubfieldOp>(value, element.index()));
303 if (
auto vectorType = dyn_cast<firrtl::FVectorType>(type)) {
304 for (
unsigned i = 0, e = vectorType.getNumElements(); i != e; ++i)
306 builder.createOrFold<firrtl::SubindexOp>(value, i));
309 if (!isa<firrtl::UIntType>(type)) {
310 if (isa<firrtl::SIntType>(type))
311 value = builder.create<firrtl::AsUIntPrimOp>(value);
315 into = into ? builder.createOrFold<firrtl::XorPrimOp>(into, value) : value;
324 erasedModules.clear();
332 SmallVector<Operation *> worklist;
333 auto deadInsts = erasedInsts;
334 for (
auto *op : erasedModules)
335 worklist.push_back(op);
336 while (!worklist.empty()) {
337 auto *op = worklist.pop_back_val();
338 auto *tableOp = SymbolTable::getNearestSymbolTable(op);
339 op->walk([&](firrtl::InstanceOp instOp) {
340 auto moduleOp = cast<firrtl::FModuleLike>(
341 instOp.getReferencedOperation(symbols.getSymbolTable(tableOp)));
342 deadInsts.insert(instOp);
344 symbols.getSymbolUserMap(tableOp).getUsers(moduleOp),
345 [&](Operation *user) { return deadInsts.contains(user); })) {
346 LLVM_DEBUG(llvm::dbgs() <<
"- Removing transitively unused module `"
347 << moduleOp.getModuleName() <<
"`\n");
348 erasedModules.insert(moduleOp);
349 worklist.push_back(moduleOp);
354 for (
auto *op : erasedInsts)
356 for (
auto *op : erasedModules)
358 nlaRemover.remove(op);
361 uint64_t
match(firrtl::InstanceOp instOp)
override {
363 return moduleSizes.getModuleSize(*fmoduleOp, symbols);
367 LogicalResult
rewrite(firrtl::InstanceOp instOp)
override {
368 LLVM_DEBUG(llvm::dbgs()
369 <<
"Stubbing instance `" << instOp.getName() <<
"`\n");
370 ImplicitLocOpBuilder builder(instOp.getLoc(), instOp);
372 for (
unsigned i = 0, e = instOp.getNumResults(); i != e; ++i) {
373 auto result = instOp.getResult(i);
374 auto name = builder.getStringAttr(Twine(instOp.getName()) +
"_" +
375 instOp.getPortNameStr(i));
378 .create<firrtl::WireOp>(result.getType(), name,
379 firrtl::NameKindEnum::DroppableName,
380 instOp.getPortAnnotation(i), StringAttr{})
383 instOp.getPortDirection(i) == firrtl::Direction::In);
384 result.replaceAllUsesWith(wire);
386 auto *tableOp = SymbolTable::getNearestSymbolTable(instOp);
387 auto moduleOp = cast<firrtl::FModuleLike>(
388 instOp.getReferencedOperation(symbols.getSymbolTable(tableOp)));
389 nlaRemover.markNLAsInOperation(instOp);
390 erasedInsts.insert(instOp);
392 symbols.getSymbolUserMap(tableOp).getUsers(moduleOp),
393 [&](Operation *user) { return erasedInsts.contains(user); })) {
394 LLVM_DEBUG(llvm::dbgs() <<
"- Removing now unused module `"
395 << moduleOp.getModuleName() <<
"`\n");
396 erasedModules.insert(moduleOp);
401 std::string
getName()
const override {
return "instance-stubber"; }
416 LogicalResult
rewrite(firrtl::MemOp memOp)
override {
417 LLVM_DEBUG(llvm::dbgs() <<
"Stubbing memory `" << memOp.getName() <<
"`\n");
418 ImplicitLocOpBuilder builder(memOp.getLoc(), memOp);
421 SmallVector<Value> outputs;
422 for (
unsigned i = 0, e = memOp.getNumResults(); i != e; ++i) {
423 auto result = memOp.getResult(i);
424 auto name = builder.getStringAttr(Twine(memOp.getName()) +
"_" +
425 memOp.getPortNameStr(i));
428 .create<firrtl::WireOp>(result.getType(), name,
429 firrtl::NameKindEnum::DroppableName,
430 memOp.getPortAnnotation(i), StringAttr{})
433 result.replaceAllUsesWith(wire);
437 switch (memOp.getPortKind(i)) {
438 case firrtl::MemOp::PortKind::Read:
439 output = builder.createOrFold<firrtl::SubfieldOp>(wire, 3);
441 case firrtl::MemOp::PortKind::Write:
442 input = builder.createOrFold<firrtl::SubfieldOp>(wire, 3);
444 case firrtl::MemOp::PortKind::ReadWrite:
445 input = builder.createOrFold<firrtl::SubfieldOp>(wire, 5);
446 output = builder.createOrFold<firrtl::SubfieldOp>(wire, 3);
448 case firrtl::MemOp::PortKind::Debug:
453 if (!isa<firrtl::RefType>(result.getType())) {
456 cast<firrtl::BundleType>(wire.getType()).getNumElements();
457 for (
unsigned i = 0; i != numFields; ++i) {
458 if (i != 2 && i != 3 && i != 5)
460 builder.createOrFold<firrtl::SubfieldOp>(wire, i));
468 outputs.push_back(output);
472 for (
auto output : outputs)
475 nlaRemover.markNLAsInOperation(memOp);
479 std::string
getName()
const override {
return "memory-stubber"; }
487 return isa<firrtl::WireOp, firrtl::RegOp, firrtl::RegResetOp,
488 firrtl::InstanceOp, firrtl::SubfieldOp, firrtl::SubindexOp,
489 firrtl::SubaccessOp>(op);
495 template <
unsigned OpNum>
497 uint64_t
match(Operation *op)
override {
498 if (op->getNumResults() != 1 || OpNum >= op->getNumOperands())
503 dyn_cast<firrtl::FIRRTLBaseType>(op->getResult(0).getType());
505 dyn_cast<firrtl::FIRRTLBaseType>(op->getOperand(OpNum).getType());
506 return resultTy && opTy &&
507 resultTy.getWidthlessType() == opTy.getWidthlessType() &&
508 (resultTy.getBitWidthOrSentinel() == -1) ==
509 (opTy.getBitWidthOrSentinel() == -1) &&
510 isa<firrtl::UIntType, firrtl::SIntType>(resultTy);
512 LogicalResult
rewrite(Operation *op)
override {
514 ImplicitLocOpBuilder builder(op->getLoc(), op);
515 auto result = op->getResult(0);
516 auto operand = op->getOperand(OpNum);
517 auto resultTy = cast<firrtl::FIRRTLBaseType>(result.getType());
518 auto operandTy = cast<firrtl::FIRRTLBaseType>(operand.getType());
519 auto resultWidth = resultTy.getBitWidthOrSentinel();
520 auto operandWidth = operandTy.getBitWidthOrSentinel();
522 if (resultWidth < operandWidth)
524 builder.createOrFold<firrtl::BitsPrimOp>(operand, resultWidth - 1, 0);
525 else if (resultWidth > operandWidth)
526 newOp = builder.createOrFold<firrtl::PadPrimOp>(operand, resultWidth);
529 LLVM_DEBUG(llvm::dbgs() <<
"Forwarding " << newOp <<
" in " << *op <<
"\n");
530 result.replaceAllUsesWith(newOp);
535 return (
"firrtl-operand" + Twine(OpNum) +
"-forwarder").str();
542 uint64_t
match(Operation *op)
override {
543 if (op->getNumResults() != 1 || op->getNumOperands() == 0)
547 auto type = dyn_cast<firrtl::FIRRTLBaseType>(op->getResult(0).getType());
548 return isa_and_nonnull<firrtl::UIntType, firrtl::SIntType>(type);
550 LogicalResult
rewrite(Operation *op)
override {
552 OpBuilder builder(op);
553 auto type = cast<firrtl::FIRRTLBaseType>(op->getResult(0).getType());
554 auto width = type.getBitWidthOrSentinel();
557 auto newOp = builder.create<firrtl::ConstantOp>(
558 op->getLoc(), type, APSInt(width, isa<firrtl::UIntType>(type)));
559 op->replaceAllUsesWith(newOp);
563 std::string
getName()
const override {
return "firrtl-constantifier"; }
571 uint64_t
match(Operation *op)
override {
572 if (!isa<firrtl::ConnectOp, firrtl::MatchingConnectOp>(op))
574 auto type = dyn_cast<firrtl::FIRRTLBaseType>(op->getOperand(1).getType());
575 return type && type.isPassive() &&
576 !op->getOperand(1).getDefiningOp<firrtl::InvalidValueOp>();
578 LogicalResult
rewrite(Operation *op)
override {
580 auto rhs = op->getOperand(1);
581 OpBuilder builder(op);
583 builder.create<firrtl::InvalidValueOp>(rhs.getLoc(), rhs.getType());
584 auto *rhsOp = rhs.getDefiningOp();
585 op->setOperand(1, invOp);
590 std::string
getName()
const override {
return "connect-invalidator"; }
599 uint64_t
match(Operation *op)
override {
600 return op->hasAttr(
"annotations") || op->hasAttr(
"portAnnotations");
602 LogicalResult
rewrite(Operation *op)
override {
604 if (
auto annos = op->getAttr(
"annotations")) {
605 nlaRemover.markNLAsInAnnotation(annos);
606 op->setAttr(
"annotations", emptyArray);
608 if (
auto annos = op->getAttr(
"portAnnotations")) {
609 nlaRemover.markNLAsInAnnotation(annos);
610 auto attr = emptyArray;
611 if (isa<firrtl::InstanceOp>(op))
614 SmallVector<Attribute>(op->getNumResults(), emptyArray));
615 op->setAttr(
"portAnnotations", attr);
619 std::string
getName()
const override {
return "annotation-remover"; }
626 uint64_t
match(firrtl::FModuleOp module)
override {
627 auto circuit = module->getParentOfType<firrtl::CircuitOp>();
630 return circuit.getNameAttr() == module.getNameAttr();
632 LogicalResult
rewrite(firrtl::FModuleOp module)
override {
634 size_t numPorts = module.getNumPorts();
635 llvm::BitVector dropPorts(numPorts);
636 for (
unsigned i = 0; i != numPorts; ++i) {
640 llvm::make_early_inc_range(module.getArgument(i).getUsers()))
644 module.erasePorts(dropPorts);
647 std::string
getName()
const override {
return "root-port-pruner"; }
659 uint64_t
match(firrtl::InstanceOp instOp)
override {
660 return isa<firrtl::FExtModuleOp>(
661 instOp.getReferencedOperation(symbols.getNearestSymbolTable(instOp)));
663 LogicalResult
rewrite(firrtl::InstanceOp instOp)
override {
665 cast<firrtl::FModuleLike>(instOp.getReferencedOperation(
666 symbols.getNearestSymbolTable(instOp)))
668 ImplicitLocOpBuilder builder(instOp.getLoc(), instOp);
669 SmallVector<Value> replacementWires;
673 .create<firrtl::WireOp>(
675 (Twine(instOp.getName()) +
"_" + info.getName()).str())
677 if (info.isOutput()) {
678 auto inv = builder.create<firrtl::InvalidValueOp>(info.type);
679 builder.create<firrtl::ConnectOp>(wire, inv);
681 replacementWires.push_back(wire);
683 nlaRemover.markNLAsInOperation(instOp);
684 instOp.replaceAllUsesWith(std::move(replacementWires));
688 std::string
getName()
const override {
return "extmodule-instance-remover"; }
699 for (
auto *op : opsToErase)
700 op->dropAllReferences();
701 for (
auto *op : opsToErase)
705 uint64_t
match(Operation *op)
override {
706 if (!isa<firrtl::FConnectLike>(op))
708 auto dest = op->getOperand(0);
709 auto src = op->getOperand(1);
710 auto *destOp = dest.getDefiningOp();
711 auto *srcOp = src.getDefiningOp();
717 if (!isa_and_nonnull<firrtl::WireOp>(destOp))
722 unsigned numConnects = 0;
723 for (
auto &use : dest.getUses()) {
724 auto *op = use.getOwner();
725 if (use.getOperandNumber() == 0 && isa<firrtl::FConnectLike>(op)) {
726 if (++numConnects > 1)
730 if (srcOp && !srcOp->isBeforeInBlock(op))
737 LogicalResult
rewrite(Operation *op)
override {
738 auto dest = op->getOperand(0);
739 dest.replaceAllUsesWith(op->getOperand(1));
740 opsToErase.insert(dest.getDefiningOp());
741 opsToErase.insert(op);
745 std::string
getName()
const override {
return "connect-forwarder"; }
752 template <
unsigned OpNum>
754 uint64_t
match(Operation *op)
override {
755 if (!isa<firrtl::ConnectOp, firrtl::MatchingConnectOp>(op))
757 auto dest = op->getOperand(0);
758 auto *destOp = dest.getDefiningOp();
761 if (!destOp || !destOp->hasOneUse() ||
762 !isa<firrtl::WireOp, firrtl::RegOp, firrtl::RegResetOp>(destOp))
765 auto *srcOp = op->getOperand(1).getDefiningOp();
766 if (!srcOp || OpNum >= srcOp->getNumOperands())
769 auto resultTy = dyn_cast<firrtl::FIRRTLBaseType>(dest.getType());
771 dyn_cast<firrtl::FIRRTLBaseType>(srcOp->getOperand(OpNum).getType());
773 return resultTy && opTy &&
774 resultTy.getWidthlessType() == opTy.getWidthlessType() &&
775 ((resultTy.getBitWidthOrSentinel() == -1) ==
776 (opTy.getBitWidthOrSentinel() == -1)) &&
777 isa<firrtl::UIntType, firrtl::SIntType>(resultTy);
780 LogicalResult
rewrite(Operation *op)
override {
781 auto *destOp = op->getOperand(0).getDefiningOp();
782 auto *srcOp = op->getOperand(1).getDefiningOp();
783 auto forwardedOperand = srcOp->getOperand(OpNum);
784 ImplicitLocOpBuilder builder(destOp->getLoc(), destOp);
786 if (
auto wire = dyn_cast<firrtl::WireOp>(destOp))
788 .create<firrtl::WireOp>(forwardedOperand.getType(),
792 auto regName = destOp->getAttrOfType<StringAttr>(
"name");
795 auto clock = destOp->getOperand(0);
797 .create<firrtl::RegOp>(forwardedOperand.getType(), clock,
798 regName ? regName.str() :
"")
803 builder.setInsertionPointAfter(op);
804 if (isa<firrtl::ConnectOp>(op))
805 builder.create<firrtl::ConnectOp>(newDest, forwardedOperand);
807 builder.create<firrtl::MatchingConnectOp>(newDest, forwardedOperand);
818 return (
"connect-source-operand-" + Twine(OpNum) +
"-forwarder").str();
828 for (
auto *op : opsToErase)
829 op->dropAllReferences();
830 for (
auto *op : opsToErase)
833 uint64_t
match(Operation *op)
override {
836 return isa<firrtl::WireOp, firrtl::RegOp, firrtl::RegResetOp>(op) &&
837 llvm::all_of(op->getUses(), [](
auto &use) {
838 return use.getOperandNumber() == 0 &&
839 isa<firrtl::SubfieldOp, firrtl::SubindexOp,
840 firrtl::SubaccessOp>(use.getOwner());
843 LogicalResult
rewrite(Operation *op)
override {
845 OpBuilder builder(op);
846 bool isWire = isa<firrtl::WireOp>(op);
849 invalidClock = builder.create<firrtl::InvalidValueOp>(
851 for (Operation *user : llvm::make_early_inc_range(op->getUsers())) {
852 builder.setInsertionPoint(user);
853 auto type = user->getResult(0).getType();
856 replOp = builder.create<firrtl::WireOp>(user->getLoc(), type);
859 builder.create<firrtl::RegOp>(user->getLoc(), type, invalidClock);
860 user->replaceAllUsesWith(replOp);
861 opsToErase.insert(user);
863 opsToErase.insert(op);
866 std::string
getName()
const override {
return "detach-subaccesses"; }
875 uint64_t
match(firrtl::NodeOp nodeOp)
override {
876 return nodeOp.getInnerSym() &&
877 !nodeOp.getInnerSym()->getSymName().getValue().empty();
880 LogicalResult
rewrite(firrtl::NodeOp nodeOp)
override {
881 nodeOp.removeInnerSymAttr();
885 std::string
getName()
const override {
return "node-symbol-remover"; }
896 uint64_t
match(firrtl::InstanceOp instOp)
override {
897 auto *tableOp = SymbolTable::getNearestSymbolTable(instOp);
899 instOp.getReferencedOperation(symbols.getSymbolTable(tableOp));
900 if (!isa<firrtl::FModuleOp>(moduleOp))
902 return symbols.getSymbolUserMap(tableOp).getUsers(moduleOp).size() == 1;
905 LogicalResult
rewrite(firrtl::InstanceOp instOp)
override {
906 LLVM_DEBUG(llvm::dbgs()
907 <<
"Inlining instance `" << instOp.getName() <<
"`\n");
908 SmallVector<Value> argReplacements;
909 ImplicitLocOpBuilder builder(instOp.getLoc(), instOp);
910 for (
unsigned i = 0, e = instOp.getNumResults(); i != e; ++i) {
911 auto result = instOp.getResult(i);
912 auto name = builder.getStringAttr(Twine(instOp.getName()) +
"_" +
913 instOp.getPortNameStr(i));
916 .create<firrtl::WireOp>(result.getType(), name,
917 firrtl::NameKindEnum::DroppableName,
918 instOp.getPortAnnotation(i), StringAttr{})
920 result.replaceAllUsesWith(wire);
921 argReplacements.push_back(wire);
923 auto *tableOp = SymbolTable::getNearestSymbolTable(instOp);
924 auto moduleOp = cast<firrtl::FModuleOp>(
925 instOp.getReferencedOperation(symbols.getSymbolTable(tableOp)));
926 for (
auto &op : llvm::make_early_inc_range(*moduleOp.getBodyBlock())) {
929 for (
auto &operand : op.getOpOperands())
930 if (
auto blockArg = dyn_cast<BlockArgument>(operand.get()))
931 operand.set(argReplacements[blockArg.getArgNumber()]);
933 nlaRemover.markNLAsInOperation(instOp);
939 std::string
getName()
const override {
return "eager-inliner"; }
958 uint64_t
match(Operation *op)
override {
960 return isa<firrtl::WireOp, firrtl::RegOp, firrtl::RegResetOp,
961 firrtl::NodeOp, firrtl::MemOp, chirrtl::CombMemOp,
962 chirrtl::SeqMemOp, firrtl::AssertOp, firrtl::AssumeOp,
963 firrtl::CoverOp>(op);
965 LogicalResult
rewrite(Operation *op)
override {
966 TypeSwitch<Operation *, void>(op)
967 .Case<firrtl::WireOp>([](
auto op) { op.setName(
"wire"); })
968 .Case<firrtl::RegOp, firrtl::RegResetOp>(
969 [](
auto op) { op.setName(
"reg"); })
970 .Case<firrtl::NodeOp>([](
auto op) { op.setName(
"node"); })
971 .Case<firrtl::MemOp, chirrtl::CombMemOp, chirrtl::SeqMemOp>(
972 [](
auto op) { op.setName(
"mem"); })
973 .Case<firrtl::AssertOp, firrtl::AssumeOp, firrtl::CoverOp>([](
auto op) {
981 return "module-internal-name-sanitizer";
1002 const char *names[48] = {
1003 "Foo",
"Bar",
"Baz",
"Qux",
"Quux",
"Quuux",
"Quuuux",
1004 "Quz",
"Corge",
"Grault",
"Bazola",
"Ztesch",
"Thud",
"Grunt",
1005 "Bletch",
"Fum",
"Fred",
"Jim",
"Sheila",
"Barney",
"Flarp",
1006 "Zxc",
"Spqr",
"Wombat",
"Shme",
"Bongo",
"Spam",
"Eggs",
1007 "Snork",
"Zot",
"Blarg",
"Wibble",
"Toto",
"Titi",
"Tata",
1008 "Tutu",
"Pippo",
"Pluto",
"Paperino",
"Aap",
"Noot",
"Mies",
1009 "Oogle",
"Foogle",
"Boogle",
"Zork",
"Gork",
"Bork"};
1011 size_t nameIndex = 0;
1014 if (nameIndex >= 48)
1016 return names[nameIndex++];
1019 size_t portNameIndex = 0;
1022 if (portNameIndex >= 26)
1024 return 'a' + portNameIndex++;
1029 LogicalResult
rewrite(firrtl::CircuitOp circuitOp)
override {
1033 auto *circuitName =
getName();
1035 circuitOp.setName(circuitName);
1037 for (
auto *node : iGraph) {
1038 auto module = node->getModule<firrtl::FModuleLike>();
1040 bool shouldReplacePorts =
false;
1041 SmallVector<Attribute> newNames;
1042 if (
auto fmodule = dyn_cast<firrtl::FModuleOp>(*module)) {
1047 auto oldPorts = fmodule.getPorts();
1048 shouldReplacePorts = !oldPorts.empty();
1049 for (
unsigned i = 0, e = fmodule.getNumPorts(); i != e; ++i) {
1050 auto port = oldPorts[i];
1052 .
Case<firrtl::ClockType>(
1053 [&](
auto a) {
return ns.
newName(
"clk"); })
1054 .Case<firrtl::ResetType, firrtl::AsyncResetType>(
1055 [&](
auto a) {
return ns.
newName(
"rst"); })
1056 .Case<firrtl::RefType>(
1057 [&](
auto a) {
return ns.
newName(
"ref"); })
1058 .Default([&](
auto a) {
1059 return ns.
newName(Twine(getPortName()));
1063 fmodule->setAttr(
"portNames",
1070 module.setName(newName);
1071 for (
auto *use : node->uses()) {
1072 auto instanceOp = dyn_cast<firrtl::InstanceOp>(*use->getInstance());
1073 instanceOp.setModuleName(newName);
1074 instanceOp.setName(newName);
1075 if (shouldReplacePorts)
1076 instanceOp.setPortNamesAttr(
1086 std::string
getName()
const override {
return "module-name-sanitizer"; }
1097 void firrtl::FIRRTLReducePatternDialectInterface::populateReducePatterns(
1146 mlir::DialectRegistry ®istry) {
1147 registry.addExtension(+[](MLIRContext *ctx, FIRRTLDialect *dialect) {
assert(baseType &&"element must be base type")
static bool isFlowSensitiveOp(Operation *op)
Check whether an operation interacts with flows in any way, which can make replacement and operand fo...
static std::optional< firrtl::FModuleOp > findInstantiatedModule(firrtl::InstanceOp instOp, ::detail::SymbolCache &symbols)
Utility to easily get the instantiated firrtl::FModuleOp or an empty optional in case another type of...
static void connectToLeafs(ImplicitLocOpBuilder &builder, Value dest, Value value)
Connect a value to every leave of a destination value.
static void invalidateOutputs(ImplicitLocOpBuilder &builder, Value value, SmallDenseMap< Type, Value, 8 > &invalidCache, bool flip=false)
Invalidate all the leaf fields of a value with a given flippedness by connecting an invalid value to ...
static bool onlyInvalidated(Value arg)
Check that all connections to a value are invalids.
static void reduceXor(ImplicitLocOpBuilder &builder, Value &into, Value value)
Reduce all leaf fields of a value through an XOR tree.
A namespace that is used to store existing names and generate new names in some scope within the IR.
StringRef newName(const Twine &name)
Return a unique name, derived from the input name, and add the new name to the internal namespace.
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 graph tracks modules and where they are instantiated.
FModuleLike getTopLevelModule()
Get the module corresponding to the top-level module of a circuit.
void registerReducePatternDialectInterface(mlir::DialectRegistry ®istry)
Register the Arc Reduction pattern dialect interface to the given registry.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Direction flip(Direction direction)
Flip a port direction.
std::unique_ptr< mlir::Pass > createLowerFIRRTLTypesPass(PreserveAggregate::PreserveMode mode=PreserveAggregate::None, PreserveAggregate::PreserveMode memoryMode=PreserveAggregate::None)
This is the pass constructor.
std::unique_ptr< mlir::Pass > createIMConstPropPass()
std::unique_ptr< mlir::Pass > createRemoveUnusedPortsPass(bool ignoreDontTouch=false)
std::unique_ptr< mlir::Pass > createInlinerPass()
std::unique_ptr< mlir::Pass > createDropNamesPass(PreserveValues::PreserveMode mode=PreserveValues::None)
std::unique_ptr< mlir::Pass > createLowerCHIRRTLPass()
std::unique_ptr< mlir::Pass > createExpandWhensPass()
std::unique_ptr< mlir::Pass > createInferWidthsPass()
std::unique_ptr< mlir::Pass > createInferResetsPass()
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
void pruneUnusedOps(Operation *initialOp, Reduction &reduction)
Starting at the given op, traverse through it and its operands and erase operations that have no more...
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
A sample reduction pattern that removes FIRRTL annotations from ports and operations.
void afterReduction(mlir::ModuleOp op) override
Called after the reduction has been applied to a subset of operations.
uint64_t match(Operation *op) override
Check if the reduction can apply to a specific operation.
LogicalResult rewrite(Operation *op) override
Apply the reduction to a specific operation.
void beforeReduction(mlir::ModuleOp op) override
Called before the reduction is applied to a new subset of operations.
std::string getName() const override
Return a human-readable name for this reduction pattern.
A sample reduction pattern that pushes connected values through wires.
uint64_t match(Operation *op) override
Check if the reduction can apply to a specific operation.
void beforeReduction(mlir::ModuleOp op) override
Called before the reduction is applied to a new subset of operations.
void afterReduction(mlir::ModuleOp op) override
Called after the reduction has been applied to a subset of operations.
LogicalResult rewrite(Operation *op) override
Apply the reduction to a specific operation.
llvm::DenseSet< Operation * > opsToErase
std::string getName() const override
Return a human-readable name for this reduction pattern.
A sample reduction pattern that replaces the right-hand-side of firrtl.connect and firrtl....
LogicalResult rewrite(Operation *op) override
Apply the reduction to a specific operation.
bool acceptSizeIncrease() const override
Return true if the tool should accept the transformation this reduction performs on the module even i...
std::string getName() const override
Return a human-readable name for this reduction pattern.
uint64_t match(Operation *op) override
Check if the reduction can apply to a specific operation.
A sample reduction pattern that replaces a single-use wire and register with an operand of the source...
uint64_t match(Operation *op) override
Check if the reduction can apply to a specific operation.
LogicalResult rewrite(Operation *op) override
Apply the reduction to a specific operation.
std::string getName() const override
Return a human-readable name for this reduction pattern.
A sample reduction pattern that tries to remove aggregate wires by replacing all subaccesses with new...
void afterReduction(mlir::ModuleOp op) override
Called after the reduction has been applied to a subset of operations.
std::string getName() const override
Return a human-readable name for this reduction pattern.
uint64_t match(Operation *op) override
Check if the reduction can apply to a specific operation.
LogicalResult rewrite(Operation *op) override
Apply the reduction to a specific operation.
void beforeReduction(mlir::ModuleOp op) override
Called before the reduction is applied to a new subset of operations.
llvm::DenseSet< Operation * > opsToErase
A sample reduction pattern that eagerly inlines instances.
uint64_t match(firrtl::InstanceOp instOp) override
::detail::SymbolCache symbols
LogicalResult rewrite(firrtl::InstanceOp instOp) override
std::string getName() const override
Return a human-readable name for this reduction pattern.
bool acceptSizeIncrease() const override
Return true if the tool should accept the transformation this reduction performs on the module even i...
void beforeReduction(mlir::ModuleOp op) override
Called before the reduction is applied to a new subset of operations.
void afterReduction(mlir::ModuleOp op) override
Called after the reduction has been applied to a subset of operations.
A sample reduction pattern that replaces instances of firrtl.extmodule with wires.
::detail::SymbolCache symbols
LogicalResult rewrite(firrtl::InstanceOp instOp) override
std::string getName() const override
Return a human-readable name for this reduction pattern.
bool acceptSizeIncrease() const override
Return true if the tool should accept the transformation this reduction performs on the module even i...
void beforeReduction(mlir::ModuleOp op) override
Called before the reduction is applied to a new subset of operations.
uint64_t match(firrtl::InstanceOp instOp) override
void afterReduction(mlir::ModuleOp op) override
Called after the reduction has been applied to a subset of operations.
A sample reduction pattern that replaces FIRRTL operations with a constant zero of their type.
LogicalResult rewrite(Operation *op) override
Apply the reduction to a specific operation.
uint64_t match(Operation *op) override
Check if the reduction can apply to a specific operation.
std::string getName() const override
Return a human-readable name for this reduction pattern.
A sample reduction pattern that maps firrtl.module to firrtl.extmodule.
std::string getName() const override
Return a human-readable name for this reduction pattern.
LogicalResult rewrite(firrtl::FModuleOp module) override
::detail::SymbolCache symbols
void beforeReduction(mlir::ModuleOp op) override
Called before the reduction is applied to a new subset of operations.
void afterReduction(mlir::ModuleOp op) override
Called after the reduction has been applied to a subset of operations.
uint64_t match(firrtl::FModuleOp module) override
ModuleSizeCache moduleSizes
A sample reduction pattern that replaces all uses of an operation with one of its operands.
std::string getName() const override
Return a human-readable name for this reduction pattern.
uint64_t match(Operation *op) override
Check if the reduction can apply to a specific operation.
LogicalResult rewrite(Operation *op) override
Apply the reduction to a specific operation.
A sample reduction pattern that maps firrtl.instance to a set of invalidated wires.
void afterReduction(mlir::ModuleOp op) override
Called after the reduction has been applied to a subset of operations.
void beforeReduction(mlir::ModuleOp op) override
Called before the reduction is applied to a new subset of operations.
llvm::DenseSet< Operation * > erasedModules
LogicalResult rewrite(firrtl::InstanceOp instOp) override
llvm::DenseSet< Operation * > erasedInsts
uint64_t match(firrtl::InstanceOp instOp) override
ModuleSizeCache moduleSizes
bool acceptSizeIncrease() const override
Return true if the tool should accept the transformation this reduction performs on the module even i...
std::string getName() const override
Return a human-readable name for this reduction pattern.
::detail::SymbolCache symbols
A sample reduction pattern that maps firrtl.mem to a set of invalidated wires.
std::string getName() const override
Return a human-readable name for this reduction pattern.
bool acceptSizeIncrease() const override
Return true if the tool should accept the transformation this reduction performs on the module even i...
void beforeReduction(mlir::ModuleOp op) override
Called before the reduction is applied to a new subset of operations.
LogicalResult rewrite(firrtl::MemOp memOp) override
void afterReduction(mlir::ModuleOp op) override
Called after the reduction has been applied to a subset of operations.
Psuedo-reduction that sanitizes the names of things inside modules.
bool acceptSizeIncrease() const override
Return true if the tool should accept the transformation this reduction performs on the module even i...
uint64_t match(Operation *op) override
Check if the reduction can apply to a specific operation.
LogicalResult rewrite(Operation *op) override
Apply the reduction to a specific operation.
std::string getName() const override
Return a human-readable name for this reduction pattern.
bool isOneShot() const override
Return true if the tool should not try to reapply this reduction after it has been successful.
Psuedo-reduction that sanitizes module, instance, and port names.
std::string getName() const override
Return a human-readable name for this reduction pattern.
void beforeReduction(mlir::ModuleOp op) override
Called before the reduction is applied to a new subset of operations.
LogicalResult rewrite(firrtl::CircuitOp circuitOp) override
bool isOneShot() const override
Return true if the tool should not try to reapply this reduction after it has been successful.
bool acceptSizeIncrease() const override
Return true if the tool should accept the transformation this reduction performs on the module even i...
Utility to track the transitive size of modules.
llvm::DenseMap< Operation *, uint64_t > moduleSizes
uint64_t getModuleSize(Operation *module, ::detail::SymbolCache &symbols)
A tracker for track NLAs affected by a reduction.
void remove(mlir::ModuleOp module)
Remove all marked annotations.
void clear()
Clear the set of marked NLAs. Call this before attempting a reduction.
llvm::DenseSet< StringAttr > nlasToRemove
The set of NLAs to remove, identified by their symbol.
void markNLAsInAnnotation(Attribute anno)
Mark all NLAs referenced in the given annotation as to be removed.
void markNLAsInOperation(Operation *op)
Mark all NLAs referenced in an operation.
This reduction removes symbols on node ops.
std::string getName() const override
Return a human-readable name for this reduction pattern.
uint64_t match(firrtl::NodeOp nodeOp) override
LogicalResult rewrite(firrtl::NodeOp nodeOp) override
A sample reduction pattern that removes ports from the root firrtl.module if the port is not used or ...
std::string getName() const override
Return a human-readable name for this reduction pattern.
LogicalResult rewrite(firrtl::FModuleOp module) override
uint64_t match(firrtl::FModuleOp module) override
A reduction pattern that applies an mlir::Pass.
An abstract reduction pattern.
A dialect interface to provide reduction patterns to a reducer tool.
This holds the name and type that describes the module's ports.
A utility doing lazy construction of SymbolTables and SymbolUserMaps, which is handy for reductions t...
SymbolTable & getSymbolTable(Operation *op)
SymbolTableCollection tables
SymbolTable & getNearestSymbolTable(Operation *op)
SymbolUserMap & getSymbolUserMap(Operation *op)
SymbolUserMap & getNearestSymbolUserMap(Operation *op)
SmallDenseMap< Operation *, SymbolUserMap, 2 > userMaps