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

llvmlistbot at llvm.org llvmlistbot at llvm.org
Wed Sep 16 21:06:52 PDT 2026


Author: Uday Bondhugula
Date: 2026-09-17T09:36:46+05:30
New Revision: 36f2ef2415e8cf5facf015bbe0d586deede34d66

URL: https://github.com/llvm/llvm-project/commit/36f2ef2415e8cf5facf015bbe0d586deede34d66
DIFF: https://github.com/llvm/llvm-project/commit/36f2ef2415e8cf5facf015bbe0d586deede34d66.diff

LOG: [MLIR][Affine] Refactor dependence testing to work on relations, not just on operations (#223188)

This change is effectively 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.

Added: 
    

Modified: 
    mlir/include/mlir/Dialect/Affine/Analysis/AffineAnalysis.h
    mlir/lib/Dialect/Affine/Analysis/AffineAnalysis.cpp

Removed: 
    


################################################################################
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())


        


More information about the Mlir-commits mailing list