15 #include "mlir/Dialect/Affine/Analysis/AffineAnalysis.h"
16 #include "mlir/Dialect/Affine/Analysis/AffineStructures.h"
17 #include "mlir/Dialect/Affine/Analysis/Utils.h"
18 #include "mlir/Dialect/Affine/IR/AffineMemoryOpInterfaces.h"
19 #include "mlir/Dialect/Affine/IR/AffineOps.h"
20 #include "mlir/Dialect/Affine/LoopUtils.h"
21 #include "mlir/Dialect/Func/IR/FuncOps.h"
22 #include "mlir/IR/BuiltinOps.h"
33 for (
auto *source : memoryOps) {
34 for (
auto *destination : memoryOps) {
35 if (source == destination)
39 if (results.count(destination) == 0)
40 results[destination] = SmallVector<MemoryDependence>();
43 MemRefAccess src(source);
44 MemRefAccess dst(destination);
45 FlatAffineValueConstraints dependenceConstraints;
46 SmallVector<DependenceComponent, 2> depComps;
50 if (depth > getInnermostCommonLoopDepth({source, destination}))
53 DependenceResult result = checkMemrefAccessDependence(
54 src, dst, depth, &dependenceConstraints, &depComps,
true);
56 results[destination].emplace_back(source, result.value, depComps);
65 SmallVector<AffineForOp> enclosingLoops;
66 getAffineForIVs(*destination, &enclosingLoops);
67 if (enclosingLoops.size() != depth)
72 SmallVector<Operation *> srcParents;
73 getEnclosingAffineOps(*source, &srcParents);
74 SmallVector<Operation *> dstParents;
75 getEnclosingAffineOps(*destination, &dstParents);
77 Operation *commonParent =
nullptr;
78 for (
auto *srcParent : llvm::reverse(srcParents)) {
79 for (
auto *dstParent : llvm::reverse(dstParents)) {
80 if (srcParent == dstParent)
81 commonParent = srcParent;
82 if (commonParent !=
nullptr)
85 if (commonParent !=
nullptr)
89 if (commonParent ==
nullptr)
93 for (
auto &commonRegion : commonParent->getRegions()) {
94 if (commonRegion.empty())
98 assert(commonRegion.hasOneBlock() &&
99 "only single-block regions are supported");
101 Block &commonBlock = commonRegion.front();
104 Operation *srcOrAncestor = commonBlock.findAncestorOpInBlock(*source);
105 Operation *dstOrAncestor =
106 commonBlock.findAncestorOpInBlock(*destination);
107 if (srcOrAncestor ==
nullptr || dstOrAncestor ==
nullptr)
111 if (srcOrAncestor->isBeforeInBlock(dstOrAncestor)) {
113 SmallVector<DependenceComponent> intraDeps;
114 for (
size_t i = 0; i < depth; ++i) {
115 DependenceComponent depComp;
116 depComp.op = enclosingLoops[i];
119 intraDeps.push_back(depComp);
122 results[destination].emplace_back(
123 source, DependenceResult::HasDependence, intraDeps);
135 auto funcOp = cast<func::FuncOp>(op);
138 std::vector<SmallVector<AffineForOp, 2>> depthToLoops;
139 mlir::affine::gatherLoops(funcOp, depthToLoops);
142 SmallVector<Operation *> memoryOps;
143 funcOp.walk([&](Operation *op) {
144 if (isa<AffineReadOpInterface, AffineWriteOpInterface>(op))
145 memoryOps.push_back(op);
149 for (
unsigned depth = 1, e = depthToLoops.size(); depth <= e; ++depth)
154 ArrayRef<MemoryDependence>
163 auto it = results.find(oldOp);
164 if (it != results.end())
170 for (
auto &it : results)
171 for (
auto &dep : it.second)
172 if (dep.source == oldOp)
assert(baseType &&"element must be base type")
static void checkMemrefDependence(SmallVectorImpl< Operation * > &memoryOps, unsigned depth, MemoryDependenceResult &results)
Helper to iterate through memory operation pairs and check for dependences at a given loop nesting de...
DenseMap< Operation *, SmallVector< MemoryDependence > > MemoryDependenceResult
MemoryDependenceResult captures a set of memory dependences.
MemoryDependenceAnalysis(Operation *funcOp)
MemoryDependenceAnalysis traverses any AffineForOps in the FuncOp body and checks for memory access d...
void replaceOp(Operation *oldOp, Operation *newOp)
Replaces the dependences, if any, from the oldOp to the newOp.
ArrayRef< MemoryDependence > getDependences(Operation *)
Returns the dependences, if any, that the given Operation depends on.