[Mlir-commits] [mlir] [MLIR][Affine] Refactor dependence testing to work on relations, not just on operations (PR #223188)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sat Sep 12 16:11:48 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir

@llvm/pr-subscribers-mlir-affine

Author: Uday Bondhugula (bondhugula)

<details>
<summary>Changes</summary>

This change is effective NFC for all users of affine dependence analysis in the tree or outside. It performs a minor refactoring of the API to allow more general usage.

`checkMemrefAccessDependence` takes two `MemRefAccess`es, each wrapping an operation, so it can only be asked about accesses that already exist. A transformation deciding whether to make a change has the opposite question: whether the accesses it is about to create would depend on each other. Loop fusion is one -- whether the stores of a slice would still be one-to-one in the loops it is about to be placed under settles whether their parallelism survives it, and it has to know before it fuses.

Nothing in the dependence analysis needs the operations. Everything from the point where the two access relations are in hand -- inverting one, composing, adding the ordering constraints, testing the result for emptiness -- is already relation-only. Split that out as `checkAccessDependence`, taking the relations and the loop depth, and leave `checkMemrefAccessDependence` as the operation-based entry point: it keeps what genuinely reads the IR, the memref and write-op checks, the affine scope and common block ones, and the
source-precedes-destination one that a depth past the shared loops calls for.

Split `MemRefAccess::getAccessRelation` the same way. The relation is built out of an access map and an iteration domain, and only the two of them being read off an operation ties it to one, so `getAccessRelation` takes them directly and the method reads them off and calls it.

Assisted by Claude.

---
Full diff: https://github.com/llvm/llvm-project/pull/223188.diff


2 Files Affected:

- (modified) mlir/include/mlir/Dialect/Affine/Analysis/AffineAnalysis.h (+29) 
- (modified) mlir/lib/Dialect/Affine/Analysis/AffineAnalysis.cpp (+32-12) 


``````````diff
diff --git a/mlir/include/mlir/Dialect/Affine/Analysis/AffineAnalysis.h b/mlir/include/mlir/Dialect/Affine/Analysis/AffineAnalysis.h
index b06b7f552e6ec..898dfdd288d6b 100644
--- a/mlir/include/mlir/Dialect/Affine/Analysis/AffineAnalysis.h
+++ b/mlir/include/mlir/Dialect/Affine/Analysis/AffineAnalysis.h
@@ -176,6 +176,35 @@ DependenceResult checkMemrefAccessDependence(
     SmallVector<DependenceComponent, 2> *dependenceComponents = nullptr,
     bool allowRAR = false);
 
+/// Builds in `rel` the access relation of an access that reads or writes
+/// `accessValueMap` over the iteration `domain`, relating the iterations of
+/// the domain to the elements they touch. Unlike `MemRefAccess`'s method of
+/// the same name, it takes the access and its domain as they are, rather than
+/// reading them from an operation, so it can describe an access that is going
+/// to exist (for example, one a transformation is deciding whether to create)
+/// as well as one that already does.
+LogicalResult getAccessRelation(const AffineValueMap &accessValueMap,
+                                const FlatAffineValueConstraints &domain,
+                                presburger::IntegerRelation &rel);
+
+/// Checks whether the accesses two relations describe touch the same element,
+/// i.e. whether there is a dependence between them carried at `loopDepth`.
+/// This is `checkMemrefAccessDependence` from the point where it has nothing
+/// but the relations left to work on, so it serves an access built by hand out
+/// of an access map and a domain just as well as one read off an operation.
+///
+/// Returns 'NoDependence' if it can be determined conclusively that the two do
+/// not touch the same element. Note that a caller working from relations it
+/// built itself has to have established what the operation-based entry point
+/// checks on its own account: that the two access the same memref, that at
+/// least one of them writes, and, where `loopDepth` is past the loops they
+/// share, that the source precedes the destination.
+DependenceResult checkAccessDependence(
+    presburger::IntegerRelation srcRel, presburger::IntegerRelation dstRel,
+    unsigned loopDepth,
+    FlatAffineValueConstraints *dependenceConstraints = nullptr,
+    SmallVector<DependenceComponent, 2> *dependenceComponents = nullptr);
+
 /// Utility function that returns true if the provided DependenceResult
 /// corresponds to a dependence result.
 inline bool hasDependence(DependenceResult result) {
diff --git a/mlir/lib/Dialect/Affine/Analysis/AffineAnalysis.cpp b/mlir/lib/Dialect/Affine/Analysis/AffineAnalysis.cpp
index 4e496e0185579..27a8c7b8ea863 100644
--- a/mlir/lib/Dialect/Affine/Analysis/AffineAnalysis.cpp
+++ b/mlir/lib/Dialect/Affine/Analysis/AffineAnalysis.cpp
@@ -456,15 +456,11 @@ static void computeDirectionVector(
   }
 }
 
-LogicalResult MemRefAccess::getAccessRelation(IntegerRelation &rel) const {
-  // Create set corresponding to domain of access.
-  FlatAffineValueConstraints domain;
-  if (failed(getOpIndexSet(opInst, &domain)))
-    return failure();
-
+LogicalResult
+mlir::affine::getAccessRelation(const AffineValueMap &accessValueMap,
+                                const FlatAffineValueConstraints &domain,
+                                IntegerRelation &rel) {
   // Get access relation from access map.
-  AffineValueMap accessValueMap;
-  getAccessMap(&accessValueMap);
   if (failed(getRelationFromMap(accessValueMap, rel)))
     return failure();
 
@@ -504,6 +500,17 @@ LogicalResult MemRefAccess::getAccessRelation(IntegerRelation &rel) const {
   return success();
 }
 
+LogicalResult MemRefAccess::getAccessRelation(IntegerRelation &rel) const {
+  // Create set corresponding to domain of access.
+  FlatAffineValueConstraints domain;
+  if (failed(getOpIndexSet(opInst, &domain)))
+    return failure();
+
+  AffineValueMap accessValueMap;
+  getAccessMap(&accessValueMap);
+  return mlir::affine::getAccessRelation(accessValueMap, domain, rel);
+}
+
 // Populates 'accessMap' with composition of AffineApplyOps reachable from
 // indices of MemRefAccess.
 void MemRefAccess::getAccessMap(AffineValueMap *accessMap) const {
@@ -651,16 +658,29 @@ DependenceResult mlir::affine::checkMemrefAccessDependence(
   // Note: this check is skipped if 'allowRAR' is true, because RAR deps
   // can exist irrespective of lexicographic ordering b/w src and dst.
   unsigned numCommonLoops = getNumCommonLoops(srcDomain, dstDomain);
-  assert(loopDepth <= numCommonLoops + 1);
+  assert(loopDepth <= numCommonLoops + 1 && "Invalid depth");
   if (!allowRAR && loopDepth > numCommonLoops &&
       !srcAppearsBeforeDstInAncestralBlock(srcAccess, dstAccess)) {
     return DependenceResult::NoDependence;
   }
 
+  return checkAccessDependence(srcRel, dstRel, loopDepth, dependenceConstraints,
+                               dependenceComponents);
+}
+
+DependenceResult mlir::affine::checkAccessDependence(
+    IntegerRelation srcRel, IntegerRelation dstRel, unsigned loopDepth,
+    FlatAffineValueConstraints *dependenceConstraints,
+    SmallVector<DependenceComponent, 2> *dependenceComponents) {
+  FlatAffineValueConstraints srcDomain(srcRel.getDomainSet());
+  FlatAffineValueConstraints dstDomain(dstRel.getDomainSet());
+  assert(loopDepth <= getNumCommonLoops(srcDomain, dstDomain) + 1 &&
+         "Invalid depth");
+
   // Compute the dependence relation by composing `srcRel` with the inverse of
-  // `dstRel`. Doing this builds a relation between iteration domain of
-  // `srcAccess` to the iteration domain of `dstAccess` which access the same
-  // memory locations.
+  // `dstRel`. Doing this builds a relation between the iteration domain of the
+  // source access to the iteration domain of the destination access which
+  // access the same memory locations.
   dstRel.inverse();
   // For 0-d spaces, there will be no IDs. Enable if that's the case.
   if (!dstRel.getSpace().isUsingIds())

``````````

</details>


https://github.com/llvm/llvm-project/pull/223188


More information about the Mlir-commits mailing list