15 #include "mlir/Pass/Pass.h"
19 #include "mlir/IR/Dominance.h"
20 #include "mlir/IR/ImplicitLocOpBuilder.h"
21 #include "llvm/Support/Debug.h"
23 #define DEBUG_TYPE "firrtl-register-optimizer"
27 #define GEN_PASS_DEF_REGISTEROPTIMIZER
28 #include "circt/Dialect/FIRRTL/Passes.h.inc"
32 using namespace circt;
33 using namespace firrtl;
38 return !(
hasDontTouch(op.getResult()) || op.isForceable() ||
39 (op.getAnnotationsAttr() && !op.getAnnotationsAttr().empty()));
48 struct RegisterOptimizerPass
49 :
public circt::firrtl::impl::RegisterOptimizerBase<RegisterOptimizerPass> {
50 void runOnOperation()
override;
51 void checkRegReset(mlir::DominanceInfo &dom,
52 SmallVector<Operation *> &toErase, RegResetOp
reg);
53 void checkReg(mlir::DominanceInfo &dom, SmallVector<Operation *> &toErase,
59 void RegisterOptimizerPass::checkReg(mlir::DominanceInfo &dom,
60 SmallVector<Operation *> &toErase,
69 if (con.getSrc() ==
reg.getResult()) {
70 auto inv = OpBuilder(
reg).create<InvalidValueOp>(
reg.getLoc(),
71 reg.getResult().getType());
72 reg.getResult().replaceAllUsesWith(inv.getResult());
73 toErase.push_back(
reg);
74 toErase.push_back(con);
83 if (
auto cst = con.getSrc().getDefiningOp<ConstantOp>()) {
85 auto *fmodb = con->getParentOfType<FModuleOp>().
getBodyBlock();
86 cst->moveBefore(fmodb, fmodb->begin());
87 reg.getResult().replaceAllUsesWith(cst.getResult());
88 toErase.push_back(con);
90 bool dominatesAll =
true;
91 for (
auto *use :
reg->getUsers()) {
94 if (!dom.dominates(con.getSrc(), use)) {
101 reg.getResult().replaceAllUsesWith(con.getSrc());
102 toErase.push_back(con);
104 auto bounce = OpBuilder(
reg).create<WireOp>(
reg.getLoc(),
105 reg.getResult().getType());
106 reg.replaceAllUsesWith(bounce);
109 toErase.push_back(
reg);
114 void RegisterOptimizerPass::checkRegReset(mlir::DominanceInfo &dom,
115 SmallVector<Operation *> &toErase,
124 if (
reg.getResetValue().getType() ==
reg.getResult().getType()) {
127 reg.getResult().replaceAllUsesWith(
reg.getResetValue());
128 toErase.push_back(
reg);
129 toErase.push_back(con);
133 if (con.getSrc() ==
reg.getResetValue() &&
136 reg.getResult().replaceAllUsesWith(
reg.getResetValue());
137 toErase.push_back(
reg);
138 toErase.push_back(con);
144 void RegisterOptimizerPass::runOnOperation() {
145 auto mod = getOperation();
148 SmallVector<Operation *> toErase;
149 mlir::DominanceInfo dom(mod);
151 for (
auto &op : *mod.getBodyBlock()) {
152 if (
auto reg = dyn_cast<RegResetOp>(&op))
153 checkRegReset(dom, toErase,
reg);
154 else if (
auto reg = dyn_cast<RegOp>(&op))
155 checkReg(dom, toErase,
reg);
157 for (
auto *op : toErase)
160 if (!toErase.empty())
161 return markAllAnalysesPreserved();
165 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)