[circt-reduce] Replace PortPruner with RemoveUnusedPortsPass (#2591)

This commit adds RemoveUnusedPortsPass to reduction passes and replaces
PortPruner with RemoveUnusedPortsPass. RemoveUnusedPortsPass would be
more powerfull since it prunus ports interprocedurally.
This commit is contained in:
Hideto Ueno 2022-02-08 01:09:17 +09:00 committed by GitHub
parent 142fc24bf4
commit 6791a4f427
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 6 additions and 91 deletions

View File

@ -1,11 +1,11 @@
// RUN: circt-reduce %s --test %S/test.sh --test-arg cat --test-arg "firrtl.module @Bar" --keep-best=0 --include port-pruner | FileCheck %s
// RUN: circt-reduce %s --test %S/test.sh --test-arg cat --test-arg "firrtl.module @Bar" --keep-best=0 --include firrtl-remove-unused-ports | FileCheck %s
firrtl.circuit "Foo" {
// CHECK-LABEL: firrtl.module @Foo
firrtl.module @Foo(in %x: !firrtl.uint<1>, out %y: !firrtl.uint<3>) {
// CHECK: %bar_a = firrtl.wire
// CHECK: %bar_c = firrtl.wire
// CHECK: %bar_e = firrtl.wire
// CHECK-NOT: %bar_a
// CHECK-NOT: %bar_c
// CHECK-NOT: %bar_e
// CHECK: %bar_b, %bar_d = firrtl.instance bar @Bar
%bar_a, %bar_b, %bar_c, %bar_d, %bar_e = firrtl.instance bar @Bar (in a: !firrtl.uint<1>, in b: !firrtl.uint<1>, out c: !firrtl.uint<1>, out d: !firrtl.uint<1>, out e: !firrtl.uint<1>)
firrtl.connect %bar_a, %x : !firrtl.uint<1>, !firrtl.uint<1>

View File

@ -353,11 +353,6 @@ static void pruneUnusedOps(Operation *initialOp) {
}
}
static void pruneUnusedOps(Value value) {
if (auto *op = value.getDefiningOp())
pruneUnusedOps(op);
}
/// Check whether an operation interacts with flows in any way, which can make
/// replacement and operand forwarding harder in some cases.
static bool isFlowSensitiveOp(Operation *op) {
@ -484,87 +479,6 @@ struct OperationPruner : public Reduction {
SymbolCache symbols;
};
/// A sample reduction pattern that removes ports from FIRRTL modules if they
/// are either unused inputs or outputs that are only invalidated.
struct PortPruner : public Reduction {
void beforeReduction(mlir::ModuleOp op) override { symbols.clear(); }
bool match(Operation *op) override {
auto moduleOp = dyn_cast<firrtl::FModuleOp>(op);
return moduleOp && llvm::any_of(moduleOp.getArguments(), onlyInvalidated);
}
LogicalResult rewrite(Operation *op) override {
auto moduleOp = cast<firrtl::FModuleOp>(op);
LLVM_DEBUG(llvm::dbgs()
<< "Pruning ports of `" << moduleOp.getName() << "`\n");
// Make a list of ports we can likely remove.
SmallVector<unsigned> removable;
for (unsigned i = 0, e = moduleOp.getNumPorts(); i != e; ++i)
if (onlyInvalidated(moduleOp.getArgument(i)))
removable.push_back(i);
assert(!removable.empty() &&
"shouldn't work on module with no prunable ports");
// Erase any users of the ports we are going to remove.
for (auto argIdx : removable) {
LLVM_DEBUG(llvm::dbgs() << " - Removing port `"
<< moduleOp.getPortName(argIdx) << "`\n");
SmallVector<Value> maybeUnused;
for (auto *userOp : llvm::make_early_inc_range(
moduleOp.getArgument(argIdx).getUsers())) {
maybeUnused.append(userOp->operand_begin(), userOp->operand_end());
userOp->erase();
}
for (auto v : maybeUnused)
pruneUnusedOps(v);
}
// Actually remove the ports.
moduleOp.erasePorts(removable);
// Update all instances of this module to reflect the change.
for (auto *userOp :
symbols.getNearestSymbolUserMap(moduleOp).getUsers(moduleOp)) {
auto instOp = dyn_cast<firrtl::InstanceOp>(userOp);
if (!instOp || instOp.moduleName() != moduleOp.getName())
continue;
LLVM_DEBUG(llvm::dbgs()
<< " - Updating instance `" << instOp.name()
<< "` in module `"
<< instOp->getParentOfType<firrtl::FModuleOp>().getName()
<< "`\n");
// Replace the removed instance port uses with corresponding wire
// declarations, and invalidate the output fields.
ImplicitLocOpBuilder builder(instOp.getLoc(), instOp);
SmallDenseMap<Type, Value, 8> invalidCache;
for (auto i : removable) {
auto result = instOp.getResult(i);
auto name = builder.getStringAttr(Twine(instOp.name()) + "_" +
instOp.getPortNameStr(i));
auto wire = builder.create<firrtl::WireOp>(
result.getType(), name, instOp.getPortAnnotation(i), StringAttr{});
invalidateOutputs(builder, wire, invalidCache,
instOp.getPortDirection(i) == firrtl::Direction::In);
result.replaceAllUsesWith(wire);
}
// Remove the ports from the instance, which creates a new instance op and
// we can remove the old one.
instOp.erasePorts(builder, removable);
instOp->erase();
}
return success();
}
std::string getName() const override { return "port-pruner"; }
bool acceptSizeIncrease() const override { return true; }
SymbolCache symbols;
};
/// A sample reduction pattern that removes FIRRTL annotations from ports and
/// operations.
struct AnnotationRemover : public Reduction {
@ -750,6 +664,8 @@ void circt::createAllReductions(
add(std::make_unique<PassReduction>(context, firrtl::createInlinerPass()));
add(std::make_unique<PassReduction>(context,
createSimpleCanonicalizerPass()));
add(std::make_unique<PassReduction>(context,
firrtl::createRemoveUnusedPortsPass()));
add(std::make_unique<InstanceStubber>());
add(std::make_unique<MemoryStubber>());
add(std::make_unique<ModuleExternalizer>());
@ -760,7 +676,6 @@ void circt::createAllReductions(
add(std::make_unique<OperandForwarder<1>>());
add(std::make_unique<OperandForwarder<2>>());
add(std::make_unique<OperationPruner>());
add(std::make_unique<PortPruner>());
add(std::make_unique<AnnotationRemover>());
add(std::make_unique<RootPortPruner>());
add(std::make_unique<ExtmoduleInstanceRemover>());