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) {
45 if (getNumResults() > 0 && !getOperation()->hasAttr(
"name") &&
46 !getOperation()->hasAttr(
"names")) {
47 bool hasExplicitInitials = !getInitials().empty();
48 bool allInitialsConstant =
49 !hasExplicitInitials ||
50 llvm::all_of(adaptor.getInitials(),
51 [&](Attribute attr) { return !!attr; });
52 if (
isAlways(adaptor.getEnable(),
false) && allInitialsConstant) {
56 if (hasExplicitInitials)
57 results.append(adaptor.getInitials().begin(),
58 adaptor.getInitials().end());
60 for (
auto resTy : getResultTypes())
64 if (!hasExplicitInitials &&
isAlways(adaptor.getReset(),
true)) {
67 for (
auto resTy : getResultTypes())
74 if (
isAlways(adaptor.getReset(),
false))
75 return getResetMutable().clear(), success();
78 if (
isAlways(adaptor.getEnable(),
true))
79 return getEnableMutable().clear(), success();
87 if (op->use_empty() && !op->hasAttr(
"name") && !op->hasAttr(
"names")) {
99 LogicalResult MemoryWriteOp::fold(FoldAdaptor adaptor,
100 SmallVectorImpl<OpFoldResult> &results) {
101 if (
isAlways(adaptor.getEnable(),
true))
102 return getEnableMutable().clear(), success();
107 PatternRewriter &rewriter) {
108 if (
isAlways(op.getEnable(),
false))
109 return rewriter.eraseOp(op), success();
118 PatternRewriter &rewriter) {
119 if (
auto pred = op.getStorage().getDefiningOp<StorageGetOp>()) {
120 op.getStorageMutable().assign(pred.getStorage());
121 op.setOffset(op.getOffset() + pred.getOffset());
132 PatternRewriter &rewriter) {
133 BitVector toDelete(op.getBodyBlock().getNumArguments());
134 for (
auto arg : llvm::reverse(op.getBodyBlock().getArguments())) {
135 if (arg.use_empty()) {
136 auto i = arg.getArgNumber();
138 op.getInputsMutable().erase(i);
141 op.getBodyBlock().eraseArguments(toDelete);
142 return toDelete.any();
146 PatternRewriter &rewriter) {
147 SmallVector<Type> resultTypes;
148 for (
auto res : llvm::reverse(op->getResults())) {
150 op.getBodyBlock().getTerminator()->eraseOperand(res.getResultNumber());
152 resultTypes.push_back(res.getType());
156 if (resultTypes.size() == op->getNumResults())
159 rewriter.setInsertionPoint(op);
161 auto newDomain = rewriter.create<ClockDomainOp>(
162 op.getLoc(), resultTypes, op.getInputs(), op.getClock());
163 rewriter.inlineRegionBefore(op.getBody(), newDomain.getBody(),
164 newDomain->getRegion(0).begin());
166 unsigned currIdx = 0;
167 for (
auto result : op.getOutputs()) {
168 if (!result.use_empty())
169 rewriter.replaceAllUsesWith(result, newDomain->getResult(currIdx++));
172 rewriter.eraseOp(op);
177 PatternRewriter &rewriter) {
178 rewriter.setInsertionPointToStart(&op.getBodyBlock());
181 DenseMap<Value, unsigned> seenArgs;
183 llvm::make_early_inc_range(op.getBodyBlock().getArguments())) {
184 auto i = arg.getArgNumber();
185 auto inputVal = op.getInputs()[i];
191 if (seenArgs.count(inputVal)) {
192 rewriter.replaceAllUsesWith(
193 arg, op.getBodyBlock().getArgument(seenArgs[inputVal]));
199 if (
auto *inputOp = inputVal.getDefiningOp()) {
200 bool isConstant = inputOp->hasTrait<OpTrait::ConstantLike>();
201 bool hasOneUse = inputVal.hasOneUse();
202 if (
isConstant || (isa<MemoryOp>(inputOp) && hasOneUse)) {
203 auto resultNumber = cast<OpResult>(inputVal).getResultNumber();
204 auto *clone = rewriter.clone(*inputOp);
205 rewriter.replaceAllUsesWith(arg, clone->getResult(resultNumber));
206 if (hasOneUse && inputOp->getNumResults() == 1) {
207 inputVal.dropAllUses();
208 rewriter.eraseOp(inputOp);
214 seenArgs[op.getInputs()[i]] = i;
220 for (
auto [result, terminatorOperand] : llvm::zip(
221 op.getOutputs(), op.getBodyBlock().getTerminator()->getOperands())) {
224 if (isa<BlockArgument>(terminatorOperand))
225 rewriter.replaceAllUsesWith(
226 result, op.getInputs()[cast<BlockArgument>(terminatorOperand)
237 if (
auto *defOp = terminatorOperand.getDefiningOp();
238 defOp && defOp->hasTrait<OpTrait::ConstantLike>() &&
239 !result.use_empty()) {
240 rewriter.setInsertionPointAfter(op);
241 unsigned resultIdx = cast<OpResult>(terminatorOperand).getResultNumber();
242 auto *clone = rewriter.clone(*defOp);
243 if (defOp->hasOneUse()) {
244 defOp->dropAllUses();
245 rewriter.eraseOp(defOp);
247 rewriter.replaceAllUsesWith(result, clone->getResult(resultIdx));
253 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)
static LogicalResult canonicalize(Op 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.