CIRCT 20.0.0git
Loading...
Searching...
No Matches
RegisterOptimizer.cpp
Go to the documentation of this file.
1//===- RegisterOptimizer.cpp - Register Optimizer ---------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//===----------------------------------------------------------------------===//
7//
8// This pass optimized registers as allowed by historic firrtl register
9// behaviors.
10//
11//===----------------------------------------------------------------------===//
12
15#include "circt/Support/Debug.h"
16#include "mlir/IR/Dominance.h"
17#include "mlir/Pass/Pass.h"
18#include "llvm/Support/Debug.h"
19
20#define DEBUG_TYPE "firrtl-register-optimizer"
21
22namespace circt {
23namespace firrtl {
24#define GEN_PASS_DEF_REGISTEROPTIMIZER
25#include "circt/Dialect/FIRRTL/Passes.h.inc"
26} // namespace firrtl
27} // namespace circt
28
29using namespace circt;
30using namespace firrtl;
31
32// Instantiated for RegOp and RegResetOp
33template <typename T>
34static bool canErase(T op) {
35 return !(hasDontTouch(op.getResult()) || op.isForceable() ||
36 (op.getAnnotationsAttr() && !op.getAnnotationsAttr().empty()));
37}
38
39namespace {
40
41//===----------------------------------------------------------------------===//
42// Pass Infrastructure
43//===----------------------------------------------------------------------===//
44
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,
51 RegOp reg);
52};
53
54} // namespace
55
56void RegisterOptimizerPass::checkReg(mlir::DominanceInfo &dom,
57 SmallVector<Operation *> &toErase,
58 RegOp reg) {
59 if (!canErase(reg))
60 return;
61 auto con = getSingleConnectUserOf(reg.getResult());
62 if (!con)
63 return;
64
65 // Register is only written by itself, replace with invalid.
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);
72 return;
73 }
74 // Register is only written by a constant
75 if (isConstant(con.getSrc())) {
76 // constant may not dominate the register. But it might be the next
77 // operation, so we can't just move it. Straight constants can be
78 // rematerialized. Derived constants are piped through wires.
79
80 if (auto cst = con.getSrc().getDefiningOp<ConstantOp>()) {
81 // Simple constants we can move safely
82 auto *fmodb = con->getParentOfType<FModuleOp>().getBodyBlock();
83 cst->moveBefore(fmodb, fmodb->begin());
84 reg.getResult().replaceAllUsesWith(cst.getResult());
85 toErase.push_back(con);
86 } else {
87 bool dominatesAll = true;
88 for (auto *use : reg->getUsers()) {
89 if (use == con)
90 continue;
91 if (!dom.dominates(con.getSrc(), use)) {
92 dominatesAll = false;
93 break;
94 }
95 }
96 if (dominatesAll) {
97 // Dominance is fine, just replace the op.
98 reg.getResult().replaceAllUsesWith(con.getSrc());
99 toErase.push_back(con);
100 } else {
101 auto bounce = OpBuilder(reg).create<WireOp>(reg.getLoc(),
102 reg.getResult().getType());
103 reg.replaceAllUsesWith(bounce);
104 }
105 }
106 toErase.push_back(reg);
107 return;
108 }
109}
110
111void RegisterOptimizerPass::checkRegReset(mlir::DominanceInfo &dom,
112 SmallVector<Operation *> &toErase,
113 RegResetOp reg) {
114 if (!canErase(reg))
115 return;
116 auto con = getSingleConnectUserOf(reg.getResult());
117 if (!con)
118 return;
119
120 // Register is only written by itself, and reset with a constant.
121 if (reg.getResetValue().getType() == reg.getResult().getType()) {
122 if (con.getSrc() == reg.getResult() && isConstant(reg.getResetValue())) {
123 // constant obviously dominates the register.
124 reg.getResult().replaceAllUsesWith(reg.getResetValue());
125 toErase.push_back(reg);
126 toErase.push_back(con);
127 return;
128 }
129 // Register is only written by a constant, and reset with the same constant.
130 if (con.getSrc() == reg.getResetValue() &&
131 isConstant(reg.getResetValue())) {
132 // constant obviously dominates the register.
133 reg.getResult().replaceAllUsesWith(reg.getResetValue());
134 toErase.push_back(reg);
135 toErase.push_back(con);
136 return;
137 }
138 }
139}
140
141void RegisterOptimizerPass::runOnOperation() {
142 auto mod = getOperation();
143 LLVM_DEBUG(debugPassHeader(this) << "\n";);
144
145 SmallVector<Operation *> toErase;
146 mlir::DominanceInfo dom(mod);
147
148 for (auto &op : *mod.getBodyBlock()) {
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);
153 }
154 for (auto *op : toErase)
155 op->erase();
156
157 if (!toErase.empty())
158 return markAllAnalysesPreserved();
159}
160
161std::unique_ptr<mlir::Pass> circt::firrtl::createRegisterOptimizerPass() {
162 return std::make_unique<RegisterOptimizerPass>();
163}
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.
Definition Debug.cpp:31
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Definition seq.py:21