11#include "mlir/IR/PatternMatch.h"
12#include "mlir/Support/LogicalResult.h"
22static bool isAlways(Attribute attr,
bool expected) {
23 if (
auto enable = dyn_cast_or_null<IntegerAttr>(attr))
24 return enable.getValue().getBoolValue() == expected;
32LogicalResult StateOp::fold(FoldAdaptor adaptor,
33 SmallVectorImpl<OpFoldResult> &results) {
35 if (getNumResults() > 0 && !getOperation()->hasAttr(
"name") &&
36 !getOperation()->hasAttr(
"names")) {
37 bool hasExplicitInitials = !getInitials().empty();
38 bool allInitialsConstant =
39 !hasExplicitInitials ||
40 llvm::all_of(adaptor.getInitials(),
41 [&](Attribute attr) { return !!attr; });
42 if (
isAlways(adaptor.getEnable(),
false) && allInitialsConstant) {
46 if (hasExplicitInitials)
47 results.append(adaptor.getInitials().begin(),
48 adaptor.getInitials().end());
50 for (
auto resTy : getResultTypes())
51 results.push_back(IntegerAttr::
get(resTy, 0));
54 if (!hasExplicitInitials &&
isAlways(adaptor.getReset(),
true)) {
57 for (
auto resTy : getResultTypes())
58 results.push_back(IntegerAttr::
get(resTy, 0));
64 if (
isAlways(adaptor.getReset(),
false))
65 return getResetMutable().clear(), success();
68 if (
isAlways(adaptor.getEnable(),
true))
69 return getEnableMutable().clear(), success();
74LogicalResult StateOp::canonicalize(StateOp op, PatternRewriter &rewriter) {
77 if (op->use_empty() && !op->hasAttr(
"name") && !op->hasAttr(
"names")) {
89LogicalResult StorageGetOp::canonicalize(StorageGetOp op,
90 PatternRewriter &rewriter) {
91 if (
auto pred = op.getStorage().getDefiningOp<StorageGetOp>()) {
92 rewriter.modifyOpInPlace(op, [&] {
93 op.getStorageMutable().assign(pred.getStorage());
94 op.setOffset(op.getOffset() + pred.getOffset());
106 PatternRewriter &rewriter) {
107 BitVector toDelete(op.getBodyBlock().getNumArguments());
108 for (
auto arg : llvm::reverse(op.getBodyBlock().getArguments())) {
109 if (arg.use_empty()) {
110 auto i = arg.getArgNumber();
112 rewriter.modifyOpInPlace(op, [&] { op.getInputsMutable().erase(i); });
115 if (toDelete.any()) {
116 rewriter.modifyOpInPlace(
117 op, [&] { op.getBodyBlock().eraseArguments(toDelete); });
124 PatternRewriter &rewriter) {
125 SmallVector<Type> resultTypes;
126 for (
auto res : llvm::reverse(op->getResults())) {
127 if (res.use_empty()) {
128 auto *terminator = op.getBodyBlock().getTerminator();
129 rewriter.modifyOpInPlace(
130 terminator, [&] { terminator->eraseOperand(res.getResultNumber()); });
132 resultTypes.push_back(res.getType());
137 if (resultTypes.size() == op->getNumResults())
140 rewriter.setInsertionPoint(op);
142 auto newDomain = ClockDomainOp::create(rewriter, op.getLoc(), resultTypes,
143 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);
157LogicalResult ClockDomainOp::canonicalize(ClockDomainOp op,
158 PatternRewriter &rewriter) {
159 rewriter.setInsertionPointToStart(&op.getBodyBlock());
162 DenseMap<Value, unsigned> seenArgs;
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)
static Block * getBodyBlock(FModuleLike mod)
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.