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"
38 return tables->getSymbolTable(op);
48 return userMaps.insert({op, SymbolUserMap(*
tables, op)}).first->second;
55 tables = std::make_unique<SymbolTableCollection>();
60 std::unique_ptr<SymbolTableCollection>
tables;
67static std::optional<firrtl::FModuleOp>
70 auto *tableOp = SymbolTable::getNearestSymbolTable(instOp);
71 auto moduleOp = dyn_cast<firrtl::FModuleOp>(
73 return moduleOp ? std::optional(moduleOp) : std::nullopt;
84 module->walk([&](Operation *op) {
86 if (
auto instOp = dyn_cast<firrtl::InstanceOp>(op))
100 return llvm::all_of(arg.getUses(), [](OpOperand &use) {
101 auto *op = use.getOwner();
102 if (!isa<firrtl::ConnectOp, firrtl::MatchingConnectOp>(op))
104 if (use.getOperandNumber() != 0)
106 if (!op->getOperand(1).getDefiningOp<firrtl::InvalidValueOp>())
123 unsigned numRemoved = 0;
125 for (Operation &rootOp : *
module.getBody()) {
126 if (!isa<firrtl::CircuitOp>(&rootOp))
128 SymbolTable symbolTable(&rootOp);
130 if (
auto *op = symbolTable.lookup(sym)) {
138 if (numRemoved > 0 || numLost > 0) {
139 llvm::dbgs() <<
"Removed " << numRemoved <<
" NLAs";
141 llvm::dbgs() <<
" (" << numLost <<
" no longer there)";
142 llvm::dbgs() <<
"\n";
151 if (
auto dict = dyn_cast<DictionaryAttr>(anno)) {
152 if (
auto field = dict.getAs<FlatSymbolRefAttr>(
"circt.nonlocal"))
153 nlasToRemove.insert(field.getAttr());
154 for (
auto namedAttr : dict)
155 markNLAsInAnnotation(namedAttr.getValue());
156 }
else if (
auto array = dyn_cast<ArrayAttr>(anno)) {
157 for (
auto attr : array)
158 markNLAsInAnnotation(attr);
166 op->walk([&](Operation *op) {
167 if (
auto annos = op->getAttrOfType<ArrayAttr>(
"annotations"))
168 markNLAsInAnnotation(annos);
189 uint64_t
match(firrtl::FModuleOp module)
override {
189 uint64_t
match(firrtl::FModuleOp module)
override {
…}
193 LogicalResult
rewrite(firrtl::FModuleOp module)
override {
195 OpBuilder builder(module);
196 firrtl::FExtModuleOp::create(
197 builder, module->getLoc(),
198 module->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName()),
199 module.getConventionAttr(), module.getPorts(), ArrayAttr(), StringRef(),
200 module.getAnnotationsAttr());
193 LogicalResult
rewrite(firrtl::FModuleOp module)
override {
…}
205 std::string
getName()
const override {
return "firrtl-module-externalizer"; }
219 auto type = dyn_cast<firrtl::FIRRTLType>(value.getType());
224 if (
auto bundleType = dyn_cast<firrtl::BundleType>(type)) {
225 for (
auto element : llvm::enumerate(bundleType.getElements())) {
227 builder.createOrFold<firrtl::SubfieldOp>(value, element.index());
229 flip ^ element.value().isFlip);
230 if (subfield.use_empty())
231 subfield.getDefiningOp()->erase();
237 if (
auto vectorType = dyn_cast<firrtl::FVectorType>(type)) {
238 for (
unsigned i = 0, e = vectorType.getNumElements(); i != e; ++i) {
239 auto subindex = builder.createOrFold<firrtl::SubindexOp>(value, i);
241 if (subindex.use_empty())
242 subindex.getDefiningOp()->erase();
250 Value invalid = invalidCache.lookup(type);
252 invalid = firrtl::InvalidValueOp::create(builder, type);
253 invalidCache.insert({type, invalid});
255 firrtl::ConnectOp::create(builder, value, invalid);
261 auto type = dyn_cast<firrtl::FIRRTLBaseType>(dest.getType());
264 if (
auto bundleType = dyn_cast<firrtl::BundleType>(type)) {
265 for (
auto element : llvm::enumerate(bundleType.getElements()))
267 firrtl::SubfieldOp::create(builder, dest, element.index()),
271 if (
auto vectorType = dyn_cast<firrtl::FVectorType>(type)) {
272 for (
unsigned i = 0, e = vectorType.getNumElements(); i != e; ++i)
273 connectToLeafs(builder, firrtl::SubindexOp::create(builder, dest, i),
277 auto valueType = dyn_cast<firrtl::FIRRTLBaseType>(value.getType());
280 auto destWidth = type.getBitWidthOrSentinel();
281 auto valueWidth = valueType ? valueType.getBitWidthOrSentinel() : -1;
282 if (destWidth >= 0 && valueWidth >= 0 && destWidth < valueWidth)
283 value = firrtl::HeadPrimOp::create(builder, value, destWidth);
284 if (!isa<firrtl::UIntType>(type)) {
285 if (isa<firrtl::SIntType>(type))
286 value = firrtl::AsSIntPrimOp::create(builder, value);
290 firrtl::ConnectOp::create(builder, dest, value);
294static void reduceXor(ImplicitLocOpBuilder &builder, Value &into, Value value) {
295 auto type = dyn_cast<firrtl::FIRRTLType>(value.getType());
298 if (
auto bundleType = dyn_cast<firrtl::BundleType>(type)) {
299 for (
auto element : llvm::enumerate(bundleType.getElements()))
302 builder.createOrFold<firrtl::SubfieldOp>(value, element.index()));
305 if (
auto vectorType = dyn_cast<firrtl::FVectorType>(type)) {
306 for (
unsigned i = 0, e = vectorType.getNumElements(); i != e; ++i)
308 builder.createOrFold<firrtl::SubindexOp>(value, i));
311 if (!isa<firrtl::UIntType>(type)) {
312 if (isa<firrtl::SIntType>(type))
313 value = firrtl::AsUIntPrimOp::create(builder, value);
317 into = into ? builder.createOrFold<firrtl::XorPrimOp>(into, value) : value;
294static void reduceXor(ImplicitLocOpBuilder &builder, Value &into, Value value) {
…}
334 SmallVector<Operation *> worklist;
337 worklist.push_back(op);
338 while (!worklist.empty()) {
339 auto *op = worklist.pop_back_val();
340 auto *tableOp = SymbolTable::getNearestSymbolTable(op);
341 op->walk([&](firrtl::InstanceOp instOp) {
342 auto moduleOp = cast<firrtl::FModuleLike>(
344 deadInsts.insert(instOp);
347 [&](Operation *user) { return deadInsts.contains(user); })) {
348 LLVM_DEBUG(llvm::dbgs() <<
"- Removing transitively unused module `"
349 << moduleOp.getModuleName() <<
"`\n");
351 worklist.push_back(moduleOp);
363 uint64_t
match(firrtl::InstanceOp instOp)
override {
363 uint64_t
match(firrtl::InstanceOp instOp)
override {
…}
369 LogicalResult
rewrite(firrtl::InstanceOp instOp)
override {
370 LLVM_DEBUG(llvm::dbgs()
371 <<
"Stubbing instance `" << instOp.getName() <<
"`\n");
372 ImplicitLocOpBuilder builder(instOp.getLoc(), instOp);
374 for (
unsigned i = 0, e = instOp.getNumResults(); i != e; ++i) {
375 auto result = instOp.getResult(i);
376 auto name = builder.getStringAttr(Twine(instOp.getName()) +
"_" +
377 instOp.getPortNameStr(i));
379 firrtl::WireOp::create(builder, result.getType(), name,
380 firrtl::NameKindEnum::DroppableName,
381 instOp.getPortAnnotation(i), StringAttr{})
384 instOp.getPortDirection(i) == firrtl::Direction::In);
385 result.replaceAllUsesWith(wire);
387 auto *tableOp = SymbolTable::getNearestSymbolTable(instOp);
388 auto moduleOp = cast<firrtl::FModuleLike>(
394 [&](Operation *user) { return erasedInsts.contains(user); })) {
395 LLVM_DEBUG(llvm::dbgs() <<
"- Removing now unused module `"
396 << moduleOp.getModuleName() <<
"`\n");
369 LogicalResult
rewrite(firrtl::InstanceOp instOp)
override {
…}
402 std::string
getName()
const override {
return "instance-stubber"; }
417 LogicalResult
rewrite(firrtl::MemOp memOp)
override {
418 LLVM_DEBUG(llvm::dbgs() <<
"Stubbing memory `" << memOp.getName() <<
"`\n");
419 ImplicitLocOpBuilder builder(memOp.getLoc(), memOp);
422 SmallVector<Value> outputs;
423 for (
unsigned i = 0, e = memOp.getNumResults(); i != e; ++i) {
424 auto result = memOp.getResult(i);
425 auto name = builder.getStringAttr(Twine(memOp.getName()) +
"_" +
426 memOp.getPortNameStr(i));
428 firrtl::WireOp::create(builder, 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)
417 LogicalResult
rewrite(firrtl::MemOp memOp)
override {
…}
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);
495template <
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);
497 uint64_t
match(Operation *op)
override {
…}
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);
542 uint64_t
match(Operation *op)
override {
…}
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();
558 firrtl::ConstantOp::create(builder, op->getLoc(), type,
559 APSInt(width, isa<firrtl::UIntType>(type)));
560 op->replaceAllUsesWith(newOp);
564 std::string
getName()
const override {
return "firrtl-constantifier"; }
572 uint64_t
match(Operation *op)
override {
573 if (!isa<firrtl::ConnectOp, firrtl::MatchingConnectOp>(op))
575 auto type = dyn_cast<firrtl::FIRRTLBaseType>(op->getOperand(1).getType());
576 return type && type.isPassive() &&
577 !op->getOperand(1).getDefiningOp<firrtl::InvalidValueOp>();
572 uint64_t
match(Operation *op)
override {
…}
579 LogicalResult
rewrite(Operation *op)
override {
581 auto rhs = op->getOperand(1);
582 OpBuilder builder(op);
584 firrtl::InvalidValueOp::create(builder, rhs.getLoc(), rhs.getType());
585 auto *rhsOp = rhs.getDefiningOp();
586 op->setOperand(1, invOp);
591 std::string
getName()
const override {
return "connect-invalidator"; }
600 uint64_t
match(Operation *op)
override {
601 return op->hasAttr(
"annotations") || op->hasAttr(
"portAnnotations");
600 uint64_t
match(Operation *op)
override {
…}
603 LogicalResult
rewrite(Operation *op)
override {
604 auto emptyArray = ArrayAttr::get(op->getContext(), {});
605 if (
auto annos = op->getAttr(
"annotations")) {
607 op->setAttr(
"annotations", emptyArray);
609 if (
auto annos = op->getAttr(
"portAnnotations")) {
611 auto attr = emptyArray;
612 if (isa<firrtl::InstanceOp>(op))
613 attr = ArrayAttr::get(
615 SmallVector<Attribute>(op->getNumResults(), emptyArray));
616 op->setAttr(
"portAnnotations", attr);
620 std::string
getName()
const override {
return "annotation-remover"; }
627 uint64_t
match(firrtl::FModuleOp module)
override {
628 auto circuit =
module->getParentOfType<firrtl::CircuitOp>();
631 return circuit.getNameAttr() ==
module.getNameAttr();
627 uint64_t
match(firrtl::FModuleOp module)
override {
…}
633 LogicalResult
rewrite(firrtl::FModuleOp module)
override {
635 size_t numPorts =
module.getNumPorts();
636 llvm::BitVector dropPorts(numPorts);
637 for (
unsigned i = 0; i != numPorts; ++i) {
641 llvm::make_early_inc_range(module.getArgument(i).getUsers()))
645 module.erasePorts(dropPorts);
633 LogicalResult
rewrite(firrtl::FModuleOp module)
override {
…}
648 std::string
getName()
const override {
return "root-port-pruner"; }
660 uint64_t
match(firrtl::InstanceOp instOp)
override {
661 return isa<firrtl::FExtModuleOp>(
660 uint64_t
match(firrtl::InstanceOp instOp)
override {
…}
664 LogicalResult
rewrite(firrtl::InstanceOp instOp)
override {
666 cast<firrtl::FModuleLike>(instOp.getReferencedOperation(
669 ImplicitLocOpBuilder builder(instOp.getLoc(), instOp);
670 SmallVector<Value> replacementWires;
672 auto wire = firrtl::WireOp::create(
674 (Twine(instOp.getName()) +
"_" + info.getName()).str())
676 if (info.isOutput()) {
677 auto inv = firrtl::InvalidValueOp::create(builder, info.type);
678 firrtl::ConnectOp::create(builder, wire, inv);
680 replacementWires.push_back(wire);
683 instOp.replaceAllUsesWith(std::move(replacementWires));
664 LogicalResult
rewrite(firrtl::InstanceOp instOp)
override {
…}
687 std::string
getName()
const override {
return "extmodule-instance-remover"; }
699 op->dropAllReferences();
704 uint64_t
match(Operation *op)
override {
705 if (!isa<firrtl::FConnectLike>(op))
707 auto dest = op->getOperand(0);
708 auto src = op->getOperand(1);
709 auto *destOp = dest.getDefiningOp();
710 auto *srcOp = src.getDefiningOp();
716 if (!isa_and_nonnull<firrtl::WireOp>(destOp))
721 unsigned numConnects = 0;
722 for (
auto &use : dest.getUses()) {
723 auto *op = use.getOwner();
724 if (use.getOperandNumber() == 0 && isa<firrtl::FConnectLike>(op)) {
725 if (++numConnects > 1)
729 if (srcOp && !srcOp->isBeforeInBlock(op))
704 uint64_t
match(Operation *op)
override {
…}
736 LogicalResult
rewrite(Operation *op)
override {
737 auto dest = op->getOperand(0);
738 dest.replaceAllUsesWith(op->getOperand(1));
744 std::string
getName()
const override {
return "connect-forwarder"; }
751template <
unsigned OpNum>
753 uint64_t
match(Operation *op)
override {
754 if (!isa<firrtl::ConnectOp, firrtl::MatchingConnectOp>(op))
756 auto dest = op->getOperand(0);
757 auto *destOp = dest.getDefiningOp();
760 if (!destOp || !destOp->hasOneUse() ||
761 !isa<firrtl::WireOp, firrtl::RegOp, firrtl::RegResetOp>(destOp))
764 auto *srcOp = op->getOperand(1).getDefiningOp();
765 if (!srcOp || OpNum >= srcOp->getNumOperands())
768 auto resultTy = dyn_cast<firrtl::FIRRTLBaseType>(dest.getType());
770 dyn_cast<firrtl::FIRRTLBaseType>(srcOp->getOperand(OpNum).getType());
772 return resultTy && opTy &&
773 resultTy.getWidthlessType() == opTy.getWidthlessType() &&
774 ((resultTy.getBitWidthOrSentinel() == -1) ==
775 (opTy.getBitWidthOrSentinel() == -1)) &&
776 isa<firrtl::UIntType, firrtl::SIntType>(resultTy);
753 uint64_t
match(Operation *op)
override {
…}
779 LogicalResult
rewrite(Operation *op)
override {
780 auto *destOp = op->getOperand(0).getDefiningOp();
781 auto *srcOp = op->getOperand(1).getDefiningOp();
782 auto forwardedOperand = srcOp->getOperand(OpNum);
783 ImplicitLocOpBuilder builder(destOp->getLoc(), destOp);
785 if (
auto wire = dyn_cast<firrtl::WireOp>(destOp))
786 newDest = firrtl::WireOp::create(builder, forwardedOperand.getType(),
790 auto regName = destOp->getAttrOfType<StringAttr>(
"name");
793 auto clock = destOp->getOperand(0);
794 newDest = firrtl::RegOp::create(builder, forwardedOperand.getType(),
795 clock, regName ? regName.str() :
"")
800 builder.setInsertionPointAfter(op);
801 if (isa<firrtl::ConnectOp>(op))
802 firrtl::ConnectOp::create(builder, newDest, forwardedOperand);
804 firrtl::MatchingConnectOp::create(builder, newDest, forwardedOperand);
815 return (
"connect-source-operand-" + Twine(OpNum) +
"-forwarder").str();
826 op->dropAllReferences();
830 uint64_t
match(Operation *op)
override {
833 return isa<firrtl::WireOp, firrtl::RegOp, firrtl::RegResetOp>(op) &&
834 llvm::all_of(op->getUses(), [](
auto &use) {
835 return use.getOperandNumber() == 0 &&
836 isa<firrtl::SubfieldOp, firrtl::SubindexOp,
837 firrtl::SubaccessOp>(use.getOwner());
830 uint64_t
match(Operation *op)
override {
…}
840 LogicalResult
rewrite(Operation *op)
override {
842 OpBuilder builder(op);
843 bool isWire = isa<firrtl::WireOp>(op);
846 invalidClock = firrtl::InvalidValueOp::create(
847 builder, op->getLoc(), firrtl::ClockType::get(op->getContext()));
848 for (Operation *user : llvm::make_early_inc_range(op->getUsers())) {
849 builder.setInsertionPoint(user);
850 auto type = user->getResult(0).getType();
853 replOp = firrtl::WireOp::create(builder, user->getLoc(), type);
856 firrtl::RegOp::create(builder, user->getLoc(), type, invalidClock);
857 user->replaceAllUsesWith(replOp);
863 std::string
getName()
const override {
return "detach-subaccesses"; }
872 uint64_t
match(firrtl::NodeOp nodeOp)
override {
873 return nodeOp.getInnerSym() &&
874 !nodeOp.getInnerSym()->getSymName().getValue().empty();
872 uint64_t
match(firrtl::NodeOp nodeOp)
override {
…}
877 LogicalResult
rewrite(firrtl::NodeOp nodeOp)
override {
878 nodeOp.removeInnerSymAttr();
877 LogicalResult
rewrite(firrtl::NodeOp nodeOp)
override {
…}
882 std::string
getName()
const override {
return "node-symbol-remover"; }
893 uint64_t
match(firrtl::InstanceOp instOp)
override {
894 auto *tableOp = SymbolTable::getNearestSymbolTable(instOp);
897 if (!isa<firrtl::FModuleOp>(moduleOp))
893 uint64_t
match(firrtl::InstanceOp instOp)
override {
…}
902 LogicalResult
rewrite(firrtl::InstanceOp instOp)
override {
903 LLVM_DEBUG(llvm::dbgs()
904 <<
"Inlining instance `" << instOp.getName() <<
"`\n");
905 SmallVector<Value> argReplacements;
906 ImplicitLocOpBuilder builder(instOp.getLoc(), instOp);
907 for (
unsigned i = 0, e = instOp.getNumResults(); i != e; ++i) {
908 auto result = instOp.getResult(i);
909 auto name = builder.getStringAttr(Twine(instOp.getName()) +
"_" +
910 instOp.getPortNameStr(i));
912 firrtl::WireOp::create(builder, result.getType(), name,
913 firrtl::NameKindEnum::DroppableName,
914 instOp.getPortAnnotation(i), StringAttr{})
916 result.replaceAllUsesWith(wire);
917 argReplacements.push_back(wire);
919 auto *tableOp = SymbolTable::getNearestSymbolTable(instOp);
920 auto moduleOp = cast<firrtl::FModuleOp>(
922 for (
auto &op : llvm::make_early_inc_range(*moduleOp.getBodyBlock())) {
925 for (
auto &operand : op.getOpOperands())
926 if (
auto blockArg = dyn_cast<BlockArgument>(operand.get()))
927 operand.set(argReplacements[blockArg.getArgNumber()]);
902 LogicalResult
rewrite(firrtl::InstanceOp instOp)
override {
…}
935 std::string
getName()
const override {
return "eager-inliner"; }
954 uint64_t
match(Operation *op)
override {
956 return isa<firrtl::WireOp, firrtl::RegOp, firrtl::RegResetOp,
957 firrtl::NodeOp, firrtl::MemOp, chirrtl::CombMemOp,
958 chirrtl::SeqMemOp, firrtl::AssertOp, firrtl::AssumeOp,
959 firrtl::CoverOp>(op);
954 uint64_t
match(Operation *op)
override {
…}
961 LogicalResult
rewrite(Operation *op)
override {
962 TypeSwitch<Operation *, void>(op)
963 .Case<firrtl::WireOp>([](
auto op) { op.setName(
"wire"); })
964 .Case<firrtl::RegOp, firrtl::RegResetOp>(
965 [](
auto op) { op.setName(
"reg"); })
966 .Case<firrtl::NodeOp>([](
auto op) { op.setName(
"node"); })
967 .Case<firrtl::MemOp, chirrtl::CombMemOp, chirrtl::SeqMemOp>(
968 [](
auto op) { op.setName(
"mem"); })
969 .Case<firrtl::AssertOp, firrtl::AssumeOp, firrtl::CoverOp>([](
auto op) {
970 op->setAttr(
"message", StringAttr::get(op.getContext(),
""));
971 op->setAttr(
"name", StringAttr::get(op.getContext(),
""));
977 return "module-internal-name-sanitizer";
999 "Foo",
"Bar",
"Baz",
"Qux",
"Quux",
"Quuux",
"Quuuux",
1000 "Quz",
"Corge",
"Grault",
"Bazola",
"Ztesch",
"Thud",
"Grunt",
1001 "Bletch",
"Fum",
"Fred",
"Jim",
"Sheila",
"Barney",
"Flarp",
1002 "Zxc",
"Spqr",
"Wombat",
"Shme",
"Bongo",
"Spam",
"Eggs",
1003 "Snork",
"Zot",
"Blarg",
"Wibble",
"Toto",
"Titi",
"Tata",
1004 "Tutu",
"Pippo",
"Pluto",
"Paperino",
"Aap",
"Noot",
"Mies",
1005 "Oogle",
"Foogle",
"Boogle",
"Zork",
"Gork",
"Bork"};
1025 LogicalResult
rewrite(firrtl::CircuitOp circuitOp)
override {
1029 auto *circuitName =
getName();
1031 circuitOp.setName(circuitName);
1033 for (
auto *node : iGraph) {
1034 auto module = node->getModule<firrtl::FModuleLike>();
1036 bool shouldReplacePorts =
false;
1037 SmallVector<Attribute> newNames;
1038 if (
auto fmodule = dyn_cast<firrtl::FModuleOp>(*module)) {
1043 auto oldPorts = fmodule.getPorts();
1044 shouldReplacePorts = !oldPorts.empty();
1045 for (
unsigned i = 0, e = fmodule.getNumPorts(); i != e; ++i) {
1046 auto port = oldPorts[i];
1048 .
Case<firrtl::ClockType>(
1049 [&](
auto a) {
return ns.
newName(
"clk"); })
1050 .Case<firrtl::ResetType, firrtl::AsyncResetType>(
1051 [&](
auto a) {
return ns.
newName(
"rst"); })
1052 .Case<firrtl::RefType>(
1053 [&](
auto a) {
return ns.
newName(
"ref"); })
1054 .Default([&](
auto a) {
1057 newNames.push_back(StringAttr::get(circuitOp.getContext(), newName));
1059 fmodule->setAttr(
"portNames",
1060 ArrayAttr::get(fmodule.getContext(), newNames));
1065 auto newName = StringAttr::get(circuitOp.getContext(),
getName());
1066 module.setName(newName);
1067 for (
auto *use : node->uses()) {
1068 auto instanceOp = dyn_cast<firrtl::InstanceOp>(*use->getInstance());
1069 instanceOp.setModuleName(newName);
1070 instanceOp.setName(newName);
1071 if (shouldReplacePorts)
1072 instanceOp.setPortNamesAttr(
1073 ArrayAttr::get(circuitOp.getContext(), newNames));
1025 LogicalResult
rewrite(firrtl::CircuitOp circuitOp)
override {
…}
1082 std::string
getName()
const override {
return "module-name-sanitizer"; }
1105 firrtl::createLowerCHIRRTLPass(),
true,
true);
1115 firrtl::createLowerFIRRTLTypes(),
true,
true);
1122 firrtl::createRemoveUnusedPorts({
true}));
1142 mlir::DialectRegistry ®istry) {
1143 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 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.
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...
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.
@ None
Don't explicitly preserve any named values.
void registerReducePatternDialectInterface(mlir::DialectRegistry ®istry)
Register the FIRRTL Reduction pattern dialect interface to the given registry.
ModulePort::Direction flip(ModulePort::Direction direction)
Flip a port direction.
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.
void populateReducePatterns(circt::ReducePatternSet &patterns) const override
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...
std::unique_ptr< SymbolTableCollection > tables
SymbolUserMap & getSymbolUserMap(Operation *op)
SymbolUserMap & getNearestSymbolUserMap(Operation *op)
SymbolTable & getNearestSymbolTable(Operation *op)
SmallDenseMap< Operation *, SymbolUserMap, 2 > userMaps
SymbolTable & getSymbolTable(Operation *op)