17 #include "mlir/IR/Dominance.h"
18 #include "mlir/IR/ImplicitLocOpBuilder.h"
19 #include "llvm/Support/Debug.h"
21 #define DEBUG_TYPE "firrtl-register-optimizer"
23 using namespace circt;
24 using namespace firrtl;
29 return !(
hasDontTouch(op.getResult()) || op.isForceable() ||
30 (op.getAnnotationsAttr() && !op.getAnnotationsAttr().empty()));
39 struct RegisterOptimizerPass
40 :
public RegisterOptimizerBase<RegisterOptimizerPass> {
41 void runOnOperation()
override;
42 void checkRegReset(mlir::DominanceInfo &dom,
43 SmallVector<Operation *> &toErase, RegResetOp
reg);
44 void checkReg(mlir::DominanceInfo &dom, SmallVector<Operation *> &toErase,
50 void RegisterOptimizerPass::checkReg(mlir::DominanceInfo &dom,
51 SmallVector<Operation *> &toErase,
60 if (con.getSrc() ==
reg.getResult()) {
61 auto inv = OpBuilder(
reg).create<InvalidValueOp>(
reg.getLoc(),
62 reg.getResult().getType());
63 reg.getResult().replaceAllUsesWith(inv.getResult());
64 toErase.push_back(
reg);
65 toErase.push_back(con);
74 if (
auto cst = con.getSrc().getDefiningOp<ConstantOp>()) {
76 auto *fmodb = con->getParentOfType<FModuleOp>().getBodyBlock();
77 cst->moveBefore(fmodb, fmodb->begin());
78 reg.getResult().replaceAllUsesWith(cst.getResult());
79 toErase.push_back(con);
81 bool dominatesAll =
true;
82 for (
auto *use :
reg->getUsers()) {
85 if (!dom.dominates(con.getSrc(), use)) {
92 reg.getResult().replaceAllUsesWith(con.getSrc());
93 toErase.push_back(con);
95 auto bounce = OpBuilder(
reg).create<WireOp>(
reg.getLoc(),
96 reg.getResult().getType());
97 reg.replaceAllUsesWith(bounce);
100 toErase.push_back(
reg);
105 void RegisterOptimizerPass::checkRegReset(mlir::DominanceInfo &dom,
106 SmallVector<Operation *> &toErase,
115 if (
reg.getResetValue().getType() ==
reg.getResult().getType()) {
118 reg.getResult().replaceAllUsesWith(
reg.getResetValue());
119 toErase.push_back(
reg);
120 toErase.push_back(con);
124 if (con.getSrc() ==
reg.getResetValue() &&
127 reg.getResult().replaceAllUsesWith(
reg.getResetValue());
128 toErase.push_back(
reg);
129 toErase.push_back(con);
135 void RegisterOptimizerPass::runOnOperation() {
136 auto mod = getOperation();
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...
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)