6#include "mlir/Dialect/MemRef/IR/MemRef.h"
7#include "mlir/Interfaces/SideEffectInterfaces.h"
8#include "mlir/Pass/Pass.h"
11using namespace MemoryEffects;
48class CopyRemovalPass :
public PassWrapper<CopyRemovalPass, OperationPass<>> {
50 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(CopyRemovalPass)
52 void runOnOperation()
override {
53 getOperation()->walk([&](memref::CopyOp copyOp) {
54 reuseCopySourceAsTarget(copyOp);
55 reuseCopyTargetAsSource(copyOp);
57 for (std::pair<Value, Value> &pair : replaceList)
58 pair.first.replaceAllUsesWith(pair.second);
59 for (Operation *op : eraseList)
65 llvm::SmallPtrSet<Operation *, 4> eraseList;
68 llvm::SmallDenseSet<std::pair<Value, Value>, 4> replaceList;
72 Operation *getAllocationOpInBlock(Value value, Block *block) {
73 assert(block &&
"Block cannot be null");
74 Operation *op = value.getDefiningOp();
75 if (op && op->getBlock() == block) {
76 auto effects = dyn_cast<MemoryEffectOpInterface>(op);
77 if (effects && effects.hasEffect<Allocate>())
85 Operation *getDeallocationOpInBlock(Value value, Block *block) {
86 assert(block &&
"Block cannot be null");
87 auto valueUsers = value.getUsers();
88 auto it = llvm::find_if(valueUsers, [&](Operation *op) {
89 auto effects = dyn_cast<MemoryEffectOpInterface>(op);
90 return effects && op->getBlock() == block && effects.hasEffect<Free>();
92 return (it == valueUsers.end() ?
nullptr : *it);
97 bool hasMemoryEffectOpBetween(Operation *start, Operation *end) {
98 assert((start || end) &&
"Start and end operations cannot be null");
99 assert(start->getBlock() == end->getBlock() &&
100 "Start and end operations should be in the same block.");
101 Operation *op = start->getNextNode();
102 while (op->isBeforeInBlock(end)) {
103 if (isa<MemoryEffectOpInterface>(op))
105 op = op->getNextNode();
112 bool hasUsersBetween(Value val, Operation *start, Operation *end) {
113 assert((start || end) &&
"Start and end operations cannot be null");
114 Block *block = start->getBlock();
115 assert(block == end->getBlock() &&
116 "Start and end operations should be in the same block.");
117 return llvm::any_of(val.getUsers(), [&](Operation *op) {
118 return op->getBlock() == block && start->isBeforeInBlock(op) &&
119 op->isBeforeInBlock(end);
123 bool areOpsInTheSameBlock(ArrayRef<Operation *> operations) {
124 assert(!operations.empty() &&
125 "The operations list should contain at least a single operation");
126 Block *block = operations.front()->getBlock();
127 return llvm::none_of(
128 operations, [&](Operation *op) {
return block != op->getBlock(); });
157 void reuseCopySourceAsTarget(memref::CopyOp copyOp) {
158 if (eraseList.count(copyOp))
161 Value from = copyOp.getSource();
162 Value to = copyOp.getTarget();
164 Operation *copy = copyOp.getOperation();
165 Block *copyBlock = copy->getBlock();
166 Operation *fromDefiningOp = from.getDefiningOp();
167 Operation *fromFreeingOp = getDeallocationOpInBlock(from, copyBlock);
168 Operation *toDefiningOp = getAllocationOpInBlock(to, copyBlock);
169 if (!fromDefiningOp || !fromFreeingOp || !toDefiningOp ||
170 !areOpsInTheSameBlock({fromFreeingOp, toDefiningOp, copy}) ||
171 hasUsersBetween(to, toDefiningOp, copy) ||
172 hasUsersBetween(from, copy, fromFreeingOp) ||
173 hasMemoryEffectOpBetween(copy, fromFreeingOp))
176 replaceList.insert({to, from});
177 eraseList.insert(copy);
178 eraseList.insert(toDefiningOp);
179 eraseList.insert(fromFreeingOp);
208 void reuseCopyTargetAsSource(memref::CopyOp copyOp) {
209 if (eraseList.count(copyOp))
212 Value from = copyOp.getSource();
213 Value to = copyOp.getTarget();
215 Operation *copy = copyOp.getOperation();
216 Block *copyBlock = copy->getBlock();
217 Operation *fromDefiningOp = getAllocationOpInBlock(from, copyBlock);
218 Operation *fromFreeingOp = getDeallocationOpInBlock(from, copyBlock);
219 if (!fromDefiningOp || !fromFreeingOp ||
220 !areOpsInTheSameBlock({fromFreeingOp, fromDefiningOp, copy}) ||
221 hasUsersBetween(to, fromDefiningOp, copy) ||
222 hasUsersBetween(from, copy, fromFreeingOp) ||
223 hasMemoryEffectOpBetween(copy, fromFreeingOp))
226 replaceList.insert({from, to});
227 eraseList.insert(copy);
228 eraseList.insert(fromDefiningOp);
229 eraseList.insert(fromFreeingOp);
240 return std::make_unique<CopyRemovalPass>();
std::unique_ptr<::mlir::Pass > createCopyRemovalPass()
Create a pass that removes unnecessary Copy operations.