16 #include "mlir/IR/Dominance.h"
17 #include "mlir/Pass/Pass.h"
18 #include "llvm/Support/Debug.h"
20 #define DEBUG_TYPE "firrtl-register-optimizer"
24 #define GEN_PASS_DEF_REGISTEROPTIMIZER
25 #include "circt/Dialect/FIRRTL/Passes.h.inc"
29 using namespace circt;
30 using namespace firrtl;
35 return !(
hasDontTouch(op.getResult()) || op.isForceable() ||
36 (op.getAnnotationsAttr() && !op.getAnnotationsAttr().empty()));
45 struct RegisterOptimizerPass
46 :
public circt::firrtl::impl::RegisterOptimizerBase<RegisterOptimizerPass> {
47 void runOnOperation()
override;
48 void checkRegReset(mlir::DominanceInfo &dom,
49 SmallVector<Operation *> &toErase, RegResetOp
reg);
50 void checkReg(mlir::DominanceInfo &dom, SmallVector<Operation *> &toErase,
56 void RegisterOptimizerPass::checkReg(mlir::DominanceInfo &dom,
57 SmallVector<Operation *> &toErase,
66 if (con.getSrc() ==
reg.getResult()) {
67 auto inv = OpBuilder(
reg).create<InvalidValueOp>(
reg.getLoc(),
68 reg.getResult().getType());
69 reg.getResult().replaceAllUsesWith(inv.getResult());
70 toErase.push_back(
reg);
71 toErase.push_back(con);
80 if (
auto cst = con.getSrc().getDefiningOp<ConstantOp>()) {
82 auto *fmodb = con->getParentOfType<FModuleOp>().
getBodyBlock();
83 cst->moveBefore(fmodb, fmodb->begin());
84 reg.getResult().replaceAllUsesWith(cst.getResult());
85 toErase.push_back(con);
87 bool dominatesAll =
true;
88 for (
auto *use :
reg->getUsers()) {
91 if (!dom.dominates(con.getSrc(), use)) {
98 reg.getResult().replaceAllUsesWith(con.getSrc());
99 toErase.push_back(con);
101 auto bounce = OpBuilder(
reg).create<WireOp>(
reg.getLoc(),
102 reg.getResult().getType());
103 reg.replaceAllUsesWith(bounce);
106 toErase.push_back(
reg);
111 void RegisterOptimizerPass::checkRegReset(mlir::DominanceInfo &dom,
112 SmallVector<Operation *> &toErase,
121 if (
reg.getResetValue().getType() ==
reg.getResult().getType()) {
124 reg.getResult().replaceAllUsesWith(
reg.getResetValue());
125 toErase.push_back(
reg);
126 toErase.push_back(con);
130 if (con.getSrc() ==
reg.getResetValue() &&
133 reg.getResult().replaceAllUsesWith(
reg.getResetValue());
134 toErase.push_back(
reg);
135 toErase.push_back(con);
141 void RegisterOptimizerPass::runOnOperation() {
142 auto mod = getOperation();
145 SmallVector<Operation *> toErase;
146 mlir::DominanceInfo dom(mod);
148 for (
auto &op : *mod.getBodyBlock()) {
149 if (
auto reg = dyn_cast<RegResetOp>(&op))
150 checkRegReset(dom, toErase,
reg);
151 else if (
auto reg = dyn_cast<RegOp>(&op))
152 checkReg(dom, toErase,
reg);
154 for (
auto *op : toErase)
157 if (!toErase.empty())
158 return markAllAnalysesPreserved();
162 return std::make_unique<RegisterOptimizerPass>();
static Block * getBodyBlock(FModuleLike mod)
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,...
MatchingConnectOp getSingleConnectUserOf(Value value)
Scan all the uses of the specified value, checking to see if there is exactly one connect that has th...
std::unique_ptr< mlir::Pass > createRegisterOptimizerPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
llvm::raw_ostream & debugPassHeader(const mlir::Pass *pass, int width=80)
Write a boilerplate header for a pass to the debug stream.
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)