15 #include "mlir/IR/Dominance.h"
16 #include "mlir/IR/ImplicitLocOpBuilder.h"
17 #include "llvm/Support/Debug.h"
19 #define DEBUG_TYPE "firrtl-register-optimizer"
21 using namespace circt;
22 using namespace firrtl;
27 return !(
hasDontTouch(op.getResult()) || op.isForceable() ||
28 (op.getAnnotationsAttr() && !op.getAnnotationsAttr().empty()));
37 struct RegisterOptimizerPass
38 :
public RegisterOptimizerBase<RegisterOptimizerPass> {
39 void runOnOperation()
override;
40 void checkRegReset(mlir::DominanceInfo &dom,
41 SmallVector<Operation *> &toErase, RegResetOp
reg);
42 void checkReg(mlir::DominanceInfo &dom, SmallVector<Operation *> &toErase,
48 void RegisterOptimizerPass::checkReg(mlir::DominanceInfo &dom,
49 SmallVector<Operation *> &toErase,
58 if (con.getSrc() ==
reg.getResult()) {
59 auto inv = OpBuilder(
reg).create<InvalidValueOp>(
reg.getLoc(),
60 reg.getResult().getType());
61 reg.getResult().replaceAllUsesWith(inv.getResult());
62 toErase.push_back(
reg);
63 toErase.push_back(con);
72 if (
auto cst = con.getSrc().getDefiningOp<ConstantOp>()) {
74 auto *fmodb = con->getParentOfType<FModuleOp>().getBodyBlock();
75 cst->moveBefore(fmodb, fmodb->begin());
76 reg.getResult().replaceAllUsesWith(cst.getResult());
77 toErase.push_back(con);
79 bool dominatesAll =
true;
80 for (
auto *use :
reg->getUsers()) {
83 if (!dom.dominates(con.getSrc(), use)) {
90 reg.getResult().replaceAllUsesWith(con.getSrc());
91 toErase.push_back(con);
93 auto bounce = OpBuilder(
reg).create<WireOp>(
reg.getLoc(),
94 reg.getResult().getType());
95 reg.replaceAllUsesWith(bounce);
98 toErase.push_back(
reg);
103 void RegisterOptimizerPass::checkRegReset(mlir::DominanceInfo &dom,
104 SmallVector<Operation *> &toErase,
113 if (
reg.getResetValue().getType() ==
reg.getResult().getType()) {
116 reg.getResult().replaceAllUsesWith(
reg.getResetValue());
117 toErase.push_back(
reg);
118 toErase.push_back(con);
122 if (con.getSrc() ==
reg.getResetValue() &&
125 reg.getResult().replaceAllUsesWith(
reg.getResetValue());
126 toErase.push_back(
reg);
127 toErase.push_back(con);
133 void RegisterOptimizerPass::runOnOperation() {
134 auto mod = getOperation();
135 LLVM_DEBUG(
llvm::dbgs() <<
"===----- Running RegisterOptimizer "
136 "--------------------------------------===\n"
137 <<
"Module: '" << mod.getName() <<
"'\n";);
139 SmallVector<Operation *> toErase;
140 mlir::DominanceInfo dom(mod);
142 for (
auto &op : *mod.getBodyBlock()) {
143 if (
auto reg = dyn_cast<RegResetOp>(&op))
144 checkRegReset(dom, toErase,
reg);
145 else if (
auto reg = dyn_cast<RegOp>(&op))
146 checkReg(dom, toErase,
reg);
148 for (
auto *op : toErase)
151 if (!toErase.empty())
152 return markAllAnalysesPreserved();
156 return std::make_unique<RegisterOptimizerPass>();
static bool canErase(T op)
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
bool hasDontTouch(Value value)
Check whether a block argument ("port") or the operation defining a value has a DontTouch annotation,...
std::unique_ptr< mlir::Pass > createRegisterOptimizerPass()
StrictConnectOp getSingleConnectUserOf(Value value)
Scan all the uses of the specified value, checking to see if there is exactly one connect that has th...
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
mlir::raw_indented_ostream & dbgs()
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)