13 #include "llvm/ADT/SmallSet.h"
14 #include "llvm/Support/Debug.h"
16 #define DEBUG_TYPE "hw-reductions"
19 using namespace circt;
28 void clear() { moduleSizes.clear(); }
32 if (
auto it = moduleSizes.find(module); it != moduleSizes.end())
35 module->walk([&](Operation *op) {
37 if (
auto instOp = dyn_cast<HWInstanceLike>(op)) {
38 for (
auto moduleName : instOp.getReferencedModuleNamesAttr()) {
39 auto *node = instanceGraph.lookup(cast<StringAttr>(moduleName));
41 dyn_cast_or_null<hw::HWModuleLike>(*node->getModule()))
42 size += getModuleSize(instModule, instanceGraph);
46 moduleSizes.insert({module, size});
51 llvm::DenseMap<Operation *, uint64_t> moduleSizes;
61 instanceGraph = std::make_unique<InstanceGraph>(op);
66 return moduleSizes.getModuleSize(op, *instanceGraph);
70 OpBuilder builder(op);
72 op.getPortList(), StringRef(),
78 std::string
getName()
const override {
return "hw-module-externalizer"; }
87 template <
unsigned OpNum>
89 uint64_t
match(Operation *op)
override {
90 if (op->getNumResults() != 1 || op->getNumOperands() < 2 ||
91 OpNum >= op->getNumOperands())
93 auto resultTy = dyn_cast<IntegerType>(op->getResult(0).getType());
94 auto opTy = dyn_cast<IntegerType>(op->getOperand(OpNum).getType());
95 return resultTy && opTy && resultTy == opTy &&
96 op->getResult(0) != op->getOperand(OpNum);
98 LogicalResult
rewrite(Operation *op)
override {
100 ImplicitLocOpBuilder builder(op->getLoc(), op);
101 auto result = op->getResult(0);
102 auto operand = op->getOperand(OpNum);
103 LLVM_DEBUG(llvm::dbgs()
104 <<
"Forwarding " << operand <<
" in " << *op <<
"\n");
105 result.replaceAllUsesWith(operand);
110 return (
"hw-operand" + Twine(OpNum) +
"-forwarder").str();
117 uint64_t
match(Operation *op)
override {
118 if (op->getNumResults() == 0 || op->getNumOperands() == 0)
120 return llvm::all_of(op->getResults(), [](Value result) {
121 return isa<IntegerType>(result.getType());
124 LogicalResult
rewrite(Operation *op)
override {
126 OpBuilder builder(op);
127 for (
auto result : op->getResults()) {
128 auto type = cast<IntegerType>(result.getType());
129 auto newOp = builder.create<
hw::ConstantOp>(op->getLoc(), type, 0);
130 result.replaceAllUsesWith(newOp);
135 std::string
getName()
const override {
return "hw-constantifier"; }
140 template <
bool Front>
145 SymbolTableCollection table;
146 SymbolUserMap users(table, op);
148 if (users.useEmpty(module))
149 useEmpty.insert(module);
153 return op.getNumOutputPorts() != 0 && useEmpty.contains(op);
157 Operation *terminator = op.getBody().front().getTerminator();
158 auto operands = terminator->getOperands();
159 ValueRange newOutputs = operands.drop_back();
160 unsigned portToErase = op.getNumOutputPorts() - 1;
162 newOutputs = operands.drop_front();
166 terminator->setOperands(newOutputs);
167 op.erasePorts({}, {portToErase});
173 return Front ?
"hw-module-output-pruner-front"
174 :
"hw-module-output-pruner-back";
185 SymbolTableCollection table;
186 SymbolUserMap users(table, op);
188 if (users.useEmpty(module))
189 useEmpty.insert(module);
195 SmallVector<unsigned> inputsToErase;
196 BitVector toErase(op.getNumPorts());
197 for (
auto [i, arg] : llvm::enumerate(op.getBody().getArguments())) {
198 if (arg.use_empty()) {
200 inputsToErase.push_back(i);
204 op.erasePorts(inputsToErase, {});
205 op.getBodyBlock()->eraseArguments(toErase);
210 std::string
getName()
const override {
return "hw-module-input-pruner"; }
219 void HWReducePatternDialectInterface::populateReducePatterns(
237 mlir::DialectRegistry ®istry) {
238 registry.addExtension(+[](MLIRContext *ctx, HWDialect *dialect) {
assert(baseType &&"element must be base type")
void registerReducePatternDialectInterface(mlir::DialectRegistry ®istry)
Register the Arc Reduction pattern dialect interface to the given registry.
std::map< std::string, std::set< std::string > > InstanceGraph
Iterates over the handshake::FuncOp's in the program to build an instance graph.
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 replaces integer operations with a constant zero of their type.
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.
LogicalResult rewrite(Operation *op) override
Apply the reduction to a specific operation.
A sample reduction pattern that replaces all uses of an operation with one of its operands.
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 hw.module to hw.module.extern.
std::string getName() const override
Return a human-readable name for this reduction pattern.
LogicalResult rewrite(HWModuleOp op) override
std::unique_ptr< InstanceGraph > instanceGraph
void beforeReduction(mlir::ModuleOp op) override
Called before the reduction is applied to a new subset of operations.
uint64_t match(HWModuleOp op) override
ModuleSizeCache moduleSizes
Remove the first or last output of the top-level module depending on the 'Front' template parameter.
LogicalResult rewrite(HWModuleOp op) override
DenseSet< HWModuleOp > useEmpty
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.
uint64_t match(HWModuleOp op) override
Utility to track the transitive size of modules.
uint64_t getModuleSize(HWModuleLike module, hw::InstanceGraph &instanceGraph)
An abstract reduction pattern.
A dialect interface to provide reduction patterns to a reducer tool.