[Mlir-commits] [mlir] [mlir][linalg] Hoist transfer pairs through disjoint subview slices (PR #220244)

Andrzej Warzyński llvmlistbot at llvm.org
Wed Sep 9 02:54:25 PDT 2026


================
@@ -351,5 +352,135 @@ bool hasNegativeStaticStride(MemRefType memRefTy) {
   });
 }
 
+namespace {
+// TODO: This footprint modelling and its logic overlap with
+// `SubsetOpInterface`, which is unfortunately tensor-only today; if it gains
+// memref support, look into unifying with it to improve code reuse.
+//
+/// Footprint of a memref value relative to a `root` memref reached through a
+/// chain of rank-preserving `memref.subview` ops whose `strides` operand is all
+/// ones (so each result index steps one source element in every dimension): per
+/// `root` dimension, the `[offset, offset + size)` interval the value covers (a
+/// `size` may be dynamic). The root is the underlying buffer if the whole chain
+/// composes, otherwise the result of the first subview (walking toward the
+/// root) that cannot be composed. Two footprints are therefore comparable only
+/// when they resolve to the *same* root value.
+struct SubviewFootprint {
+  Value root;
+  SmallVector<int64_t> offsets;
+  SmallVector<int64_t> sizes;
+};
+} // namespace
+
+/// Resolve `base` through a `memref.subview` chain to a footprint, or
+/// `std::nullopt` if it cannot be modelled. Composition stops at the first
+/// subview with a dynamic offset, a `strides` operand other than all ones, or a
+/// rank reduction; that subview's own result becomes the footprint root. This
+/// keeps two slices that share a common (possibly dynamically-offset) base
+/// comparable through their static offsets relative to that base. Sizes may be
+/// dynamic: such dimensions simply cannot be used to prove disjointness.
+static std::optional<SubviewFootprint> resolveSubviewFootprint(Value base) {
+  auto baseTy = dyn_cast<MemRefType>(base.getType());
+  if (!baseTy)
+    return std::nullopt;
+  SubviewFootprint footprint;
+  // Size is fixed by `base` itself; offset accumulates the static offsets of
+  // the composable subviews walked toward the root.
+  footprint.offsets.assign(baseTy.getRank(), 0);
+  footprint.sizes.assign(baseTy.getShape().begin(), baseTy.getShape().end());
+
+  Value cur = base;
+  while (auto sv = cur.getDefiningOp<SubViewOp>()) {
+    ArrayRef<int64_t> staticOffsets = sv.getStaticOffsets();
+    ArrayRef<int64_t> staticStrides = sv.getStaticStrides();
+    // Rank-reducing subviews, or those with a dynamic offset or a `strides`
+    // operand other than all ones, cannot be composed: stop here and use `sv`'s
+    // result as the root.
+    if (sv.getSourceType().getRank() != sv.getType().getRank() ||
+        llvm::any_of(staticOffsets, ShapedType::isDynamic) ||
+        llvm::any_of(staticStrides, [](int64_t s) { return s != 1; }))
----------------
banach-space wrote:

This is confusing - it checks for strides == 1, yet from `@hoist_disjoint_static_subviews_3d`:

```mlir
 // Note non-unit strides
  %sv0 = memref.subview %mem[0, 0, 0][2, 2, 2][1, 1, 1] : memref<2x4x2xf32> to memref<2x2x2xf32, strided<[8, 2, 1]>>
```

What am I missing? 🤔 

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


More information about the Mlir-commits mailing list