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"
30using namespace firrtl;
35 return !(
hasDontTouch(op.getResult()) || op.isForceable() ||
36 (op.getAnnotationsAttr() && !op.getAnnotationsAttr().empty()));
45struct 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,
56void RegisterOptimizerPass::checkReg(mlir::DominanceInfo &dom,
57 SmallVector<Operation *> &toErase,
66 if (con.getSrc() ==
reg.getResult()) {
67 auto builder = OpBuilder(reg);
68 auto inv = InvalidValueOp::create(builder,
reg.getLoc(),
69 reg.getResult().getType());
70 reg.getResult().replaceAllUsesWith(inv.getResult());
71 toErase.push_back(reg);
72 toErase.push_back(con);
81 if (
auto cst = con.getSrc().getDefiningOp<ConstantOp>()) {
83 auto *fmodb = con->getParentOfType<FModuleOp>().
getBodyBlock();
84 cst->moveBefore(fmodb, fmodb->begin());
85 reg.getResult().replaceAllUsesWith(cst.getResult());
86 toErase.push_back(con);
88 bool dominatesAll =
true;
89 for (
auto *use :
reg->getUsers()) {
92 if (!dom.dominates(con.getSrc(), use)) {
99 reg.getResult().replaceAllUsesWith(con.getSrc());
100 toErase.push_back(con);
102 auto builder = OpBuilder(reg);
104 WireOp::create(builder,
reg.getLoc(),
reg.getResult().getType());
105 reg.replaceAllUsesWith(bounce);
108 toErase.push_back(reg);
113void RegisterOptimizerPass::checkRegReset(mlir::DominanceInfo &dom,
114 SmallVector<Operation *> &toErase,
123 if (
reg.getResetValue().getType() ==
reg.getResult().getType()) {
126 reg.getResult().replaceAllUsesWith(
reg.getResetValue());
127 toErase.push_back(reg);
128 toErase.push_back(con);
132 if (con.getSrc() ==
reg.getResetValue() &&
135 reg.getResult().replaceAllUsesWith(
reg.getResetValue());
136 toErase.push_back(reg);
137 toErase.push_back(con);
143void RegisterOptimizerPass::runOnOperation() {
144 auto mod = getOperation();
147 SmallVector<Operation *> toErase;
148 mlir::DominanceInfo dom(mod);
151 if (
auto reg = dyn_cast<RegResetOp>(&op))
152 checkRegReset(dom, toErase, reg);
153 else if (
auto reg = dyn_cast<RegOp>(&op))
154 checkReg(dom, toErase, reg);
156 for (
auto *op : toErase)
159 if (!toErase.empty())
160 return markAllAnalysesPreserved();
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...
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
llvm::raw_ostream & debugPassHeader(const mlir::Pass *pass, unsigned width=80)
Write a boilerplate header for a pass to the debug stream.
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)