17#include "mlir/IR/Dominance.h"
18#include "mlir/Pass/Pass.h"
19#include "llvm/Support/Debug.h"
21#define DEBUG_TYPE "firrtl-register-optimizer"
25#define GEN_PASS_DEF_REGISTEROPTIMIZER
26#include "circt/Dialect/FIRRTL/Passes.h.inc"
31using namespace firrtl;
36 return !(
hasDontTouch(op.getResult()) || op.isForceable() ||
37 (op.getAnnotationsAttr() && !op.getAnnotationsAttr().empty()));
46struct RegisterOptimizerPass
47 :
public circt::firrtl::impl::RegisterOptimizerBase<RegisterOptimizerPass> {
48 void runOnOperation()
override;
49 void checkRegReset(mlir::DominanceInfo &dom,
50 SmallVector<Operation *> &toErase, RegResetOp reg);
51 void checkReg(mlir::DominanceInfo &dom, SmallVector<Operation *> &toErase,
57void RegisterOptimizerPass::checkReg(mlir::DominanceInfo &dom,
58 SmallVector<Operation *> &toErase,
69 if (con.getSrc() ==
reg.getResult()) {
70 auto builder = OpBuilder(reg);
72 if (
auto initial =
reg.getInitialAttr())
74 ConstantOp::create(builder,
reg.getLoc(),
75 type_cast<IntType>(
reg.getResult().getType()),
79 replacement = InvalidValueOp::create(builder,
reg.getLoc(),
80 reg.getResult().getType())
82 reg.getResult().replaceAllUsesWith(replacement);
83 toErase.push_back(reg);
84 toErase.push_back(con);
91 auto cstOp = con.getSrc().getDefiningOp<ConstantOp>();
93 cstOp ? std::optional<APInt>(cstOp.getValue())
102 auto *fmodb = con->getParentOfType<FModuleOp>().
getBodyBlock();
103 cstOp->moveBefore(fmodb, fmodb->begin());
104 reg.getResult().replaceAllUsesWith(cstOp.getResult());
105 toErase.push_back(con);
107 bool dominatesAll =
true;
108 for (
auto *use :
reg->getUsers()) {
111 if (!dom.dominates(con.getSrc(), use)) {
112 dominatesAll =
false;
118 reg.getResult().replaceAllUsesWith(con.getSrc());
119 toErase.push_back(con);
121 auto builder = OpBuilder(reg);
123 WireOp::create(builder,
reg.getLoc(),
reg.getResult().getType());
124 reg.replaceAllUsesWith(bounce);
127 toErase.push_back(reg);
132void RegisterOptimizerPass::checkRegReset(mlir::DominanceInfo &dom,
133 SmallVector<Operation *> &toErase,
143 auto resetCstOp =
reg.getResetValue().getDefiningOp<ConstantOp>();
145 resetCstOp ? std::optional<APInt>(resetCstOp.getValue())
150 if (
reg.getResetValue().getType() ==
reg.getResult().getType()) {
153 reg.getResult().replaceAllUsesWith(
reg.getResetValue());
154 toErase.push_back(reg);
155 toErase.push_back(con);
159 if (con.getSrc() ==
reg.getResetValue() &&
162 reg.getResult().replaceAllUsesWith(
reg.getResetValue());
163 toErase.push_back(reg);
164 toErase.push_back(con);
170void RegisterOptimizerPass::runOnOperation() {
173 auto mod = getOperation();
174 SmallVector<Operation *> toErase;
175 mlir::DominanceInfo dom(mod);
178 if (
auto reg = dyn_cast<RegResetOp>(&op))
179 checkRegReset(dom, toErase, reg);
180 else if (
auto reg = dyn_cast<RegOp>(&op))
181 checkReg(dom, toErase, reg);
183 for (
auto *op : toErase)
186 if (!toErase.empty())
187 return markAllAnalysesPreserved();
static Block * getBodyBlock(FModuleLike mod)
static bool canErase(T op)
#define CIRCT_DEBUG_SCOPED_PASS_LOGGER(PASS)
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,...
bool preservesInitial(IntegerAttr initial, std::optional< APInt > foldedValue=std::nullopt)
Return true if replacing a register carrying the time-zero initial value with foldedValue does not ch...
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.
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)