11 #include "mlir/IR/PatternMatch.h"
12 #include "mlir/Support/LogicalResult.h"
14 using namespace circt;
22 static bool isAlways(Attribute attr,
bool expected) {
23 if (
auto enable = dyn_cast_or_null<IntegerAttr>(attr))
24 return enable.getValue().getBoolValue() == expected;
28 static bool isAlways(Value value,
bool expected) {
33 return constOp.getValue().getBoolValue() == expected;
42 LogicalResult StateOp::fold(FoldAdaptor adaptor,
43 SmallVectorImpl<OpFoldResult> &results) {
44 if ((
isAlways(adaptor.getEnable(),
false) ||
45 isAlways(adaptor.getReset(),
true)) &&
46 !getOperation()->hasAttr(
"name") && !getOperation()->hasAttr(
"names")) {
49 for (
auto resTy : getResultTypes())
55 if (
isAlways(adaptor.getReset(),
false))
56 return getResetMutable().clear(), success();
59 if (
isAlways(adaptor.getEnable(),
true))
60 return getEnableMutable().clear(), success();
65 LogicalResult StateOp::canonicalize(StateOp op, PatternRewriter &rewriter) {
68 if (op->use_empty() && !op->hasAttr(
"name") && !op->hasAttr(
"names")) {
80 LogicalResult MemoryWriteOp::fold(FoldAdaptor adaptor,
81 SmallVectorImpl<OpFoldResult> &results) {
82 if (
isAlways(adaptor.getEnable(),
true))
83 return getEnableMutable().clear(), success();
87 LogicalResult MemoryWriteOp::canonicalize(MemoryWriteOp op,
88 PatternRewriter &rewriter) {
90 return rewriter.eraseOp(op), success();
98 LogicalResult StorageGetOp::canonicalize(StorageGetOp op,
99 PatternRewriter &rewriter) {
100 if (
auto pred = op.getStorage().getDefiningOp<StorageGetOp>()) {
101 op.getStorageMutable().assign(pred.getStorage());
102 op.setOffset(op.getOffset() + pred.getOffset());
113 PatternRewriter &rewriter) {
114 BitVector toDelete(op.getBodyBlock().getNumArguments());
115 for (
auto arg : llvm::reverse(op.getBodyBlock().getArguments())) {
116 if (arg.use_empty()) {
117 auto i = arg.getArgNumber();
119 op.getInputsMutable().erase(i);
122 op.getBodyBlock().eraseArguments(toDelete);
123 return toDelete.any();
127 PatternRewriter &rewriter) {
128 SmallVector<Type> resultTypes;
129 for (
auto res : llvm::reverse(op->getResults())) {
131 op.getBodyBlock().getTerminator()->eraseOperand(res.getResultNumber());
133 resultTypes.push_back(res.getType());
137 if (resultTypes.size() == op->getNumResults())
140 rewriter.setInsertionPoint(op);
142 auto newDomain = rewriter.create<ClockDomainOp>(
143 op.getLoc(), resultTypes, op.getInputs(), op.getClock());
144 rewriter.inlineRegionBefore(op.getBody(), newDomain.getBody(),
145 newDomain->getRegion(0).begin());
147 unsigned currIdx = 0;
148 for (
auto result : op.getOutputs()) {
149 if (!result.use_empty())
150 rewriter.replaceAllUsesWith(result, newDomain->getResult(currIdx++));
153 rewriter.eraseOp(op);
157 LogicalResult ClockDomainOp::canonicalize(ClockDomainOp op,
158 PatternRewriter &rewriter) {
159 rewriter.setInsertionPointToStart(&op.getBodyBlock());
162 DenseMap<Value, unsigned> seenArgs;
164 llvm::make_early_inc_range(op.getBodyBlock().getArguments())) {
165 auto i = arg.getArgNumber();
166 auto inputVal = op.getInputs()[i];
172 if (seenArgs.count(inputVal)) {
173 rewriter.replaceAllUsesWith(
174 arg, op.getBodyBlock().getArgument(seenArgs[inputVal]));
180 if (
auto *inputOp = inputVal.getDefiningOp()) {
181 bool isConstant = inputOp->hasTrait<OpTrait::ConstantLike>();
182 bool hasOneUse = inputVal.hasOneUse();
183 if (
isConstant || (isa<MemoryOp>(inputOp) && hasOneUse)) {
184 auto resultNumber = cast<OpResult>(inputVal).getResultNumber();
185 auto *clone = rewriter.clone(*inputOp);
186 rewriter.replaceAllUsesWith(arg, clone->getResult(resultNumber));
187 if (hasOneUse && inputOp->getNumResults() == 1) {
188 inputVal.dropAllUses();
189 rewriter.eraseOp(inputOp);
195 seenArgs[op.getInputs()[i]] = i;
201 for (
auto [result, terminatorOperand] : llvm::zip(
202 op.getOutputs(), op.getBodyBlock().getTerminator()->getOperands())) {
205 if (isa<BlockArgument>(terminatorOperand))
206 rewriter.replaceAllUsesWith(
207 result, op.getInputs()[cast<BlockArgument>(terminatorOperand)
218 if (
auto *defOp = terminatorOperand.getDefiningOp();
219 defOp && defOp->hasTrait<OpTrait::ConstantLike>() &&
220 !result.use_empty()) {
221 rewriter.setInsertionPointAfter(op);
222 unsigned resultIdx = cast<OpResult>(terminatorOperand).getResultNumber();
223 auto *clone = rewriter.clone(*defOp);
224 if (defOp->hasOneUse()) {
225 defOp->dropAllUses();
226 rewriter.eraseOp(defOp);
228 rewriter.replaceAllUsesWith(result, clone->getResult(resultIdx));
234 return success(didCanonicalizeInput || didCanoncalizeOutput);
static bool isAlways(Attribute attr, bool expected)
static bool removeUnusedClockDomainInputs(ClockDomainOp op, PatternRewriter &rewriter)
static bool removeUnusedClockDomainOutputs(ClockDomainOp op, PatternRewriter &rewriter)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.