@@ -241,7 +241,55 @@ addNodeToMDG(Operation *nodeOp, MemRefDependenceGraph &mdg,
241
241
return &node;
242
242
}
243
243
244
- bool MemRefDependenceGraph::init () {
244
+ // / Returns true if there may be a dependence on `memref` from srcNode's
245
+ // / memory ops to dstNode's memory ops, while using the affine memory
246
+ // / dependence analysis checks. The method assumes that there is at least one
247
+ // / memory op in srcNode's loads and stores on `memref`, and similarly for
248
+ // / `dstNode`. `srcNode.op` and `destNode.op` are expected to be nested in the
249
+ // / same block and so the dependences are tested at the depth of that block.
250
+ static bool mayDependence (const Node &srcNode, const Node &dstNode,
251
+ Value memref) {
252
+ assert (srcNode.op ->getBlock () == dstNode.op ->getBlock ());
253
+ if (!isa<AffineForOp>(srcNode.op ) || !isa<AffineForOp>(dstNode.op ))
254
+ return true ;
255
+
256
+ // Non-affine stores, can't check. Conservatively, return true.
257
+ if (!srcNode.memrefStores .empty ())
258
+ return true ;
259
+ if (!dstNode.memrefStores .empty ())
260
+ return true ;
261
+
262
+ // Non-affine loads with a store in the other.
263
+ if (!srcNode.memrefLoads .empty () && !dstNode.stores .empty ())
264
+ return true ;
265
+ if (!dstNode.memrefLoads .empty () && !srcNode.stores .empty ())
266
+ return true ;
267
+
268
+ // Affine load/store pairs. We don't need to check for locally allocated
269
+ // memrefs since the dependence analysis here is between mem ops from
270
+ // srcNode's for op to dstNode's for op at the depth at which those
271
+ // `affine.for` ops are nested, i.e., dependences at depth `d + 1` where
272
+ // `d` is the number of common surrounding loops.
273
+ for (auto *srcMemOp :
274
+ llvm::concat<Operation *const >(srcNode.stores , srcNode.loads )) {
275
+ MemRefAccess srcAcc (srcMemOp);
276
+ if (srcAcc.memref != memref)
277
+ continue ;
278
+ for (auto *destMemOp :
279
+ llvm::concat<Operation *const >(dstNode.stores , dstNode.loads )) {
280
+ MemRefAccess destAcc (destMemOp);
281
+ if (destAcc.memref != memref)
282
+ continue ;
283
+ // Check for a top-level dependence between srcNode and destNode's ops.
284
+ if (!noDependence (checkMemrefAccessDependence (
285
+ srcAcc, destAcc, getNestingDepth (srcNode.op ) + 1 )))
286
+ return true ;
287
+ }
288
+ }
289
+ return false ;
290
+ }
291
+
292
+ bool MemRefDependenceGraph::init (bool fullAffineDependences) {
245
293
LDBG () << " --- Initializing MDG ---" ;
246
294
// Map from a memref to the set of ids of the nodes that have ops accessing
247
295
// the memref.
@@ -344,8 +392,12 @@ bool MemRefDependenceGraph::init() {
344
392
Node *dstNode = getNode (dstId);
345
393
bool dstHasStoreOrFree =
346
394
dstNode->hasStore (srcMemRef) || dstNode->hasFree (srcMemRef);
347
- if (srcHasStoreOrFree || dstHasStoreOrFree)
348
- addEdge (srcId, dstId, srcMemRef);
395
+ if ((srcHasStoreOrFree || dstHasStoreOrFree)) {
396
+ // Check precise affine deps if asked for; otherwise, conservative.
397
+ if (!fullAffineDependences ||
398
+ mayDependence (*srcNode, *dstNode, srcMemRef))
399
+ addEdge (srcId, dstId, srcMemRef);
400
+ }
349
401
}
350
402
}
351
403
}
@@ -562,13 +614,13 @@ MemRefDependenceGraph::getFusedLoopNestInsertionPoint(unsigned srcId,
562
614
}
563
615
564
616
// Build set of insts in range (srcId, dstId) which depend on 'srcId'.
565
- SmallPtrSet<Operation *, 2 > srcDepInsts;
617
+ llvm:: SmallPtrSet<Operation *, 2 > srcDepInsts;
566
618
for (auto &outEdge : outEdges.lookup (srcId))
567
619
if (outEdge.id != dstId)
568
620
srcDepInsts.insert (getNode (outEdge.id )->op );
569
621
570
622
// Build set of insts in range (srcId, dstId) on which 'dstId' depends.
571
- SmallPtrSet<Operation *, 2 > dstDepInsts;
623
+ llvm:: SmallPtrSet<Operation *, 2 > dstDepInsts;
572
624
for (auto &inEdge : inEdges.lookup (dstId))
573
625
if (inEdge.id != srcId)
574
626
dstDepInsts.insert (getNode (inEdge.id )->op );
0 commit comments