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 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);
111void 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);
141void RegisterOptimizerPass::runOnOperation() {
142 auto mod = getOperation();
145 SmallVector<Operation *> toErase;
146 mlir::DominanceInfo dom(mod);
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();
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, int 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)