[Mlir-commits] [mlir] [mlir][linalg] Hoist transfer pairs through disjoint subview slices (PR #220244)
Hugo Pompougnac
llvmlistbot at llvm.org
Wed Sep 9 05:56:53 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; }))
----------------
qaco wrote:
Nothing missing, these are two different "strides". `getStaticStrides()` returns the subview op's strides operand, which is [1, 1, 1] here: it's the per-dimension step taken in the source (1 = dense slice, no subsampling), and that is what the check requires so the footprint stays a contiguous [offset, offset + size) interval per dimension.
The strided<[8, 2, 1]> you spotted is the result type's layout (memory distances between neighbours along each axis), which the check never inspects: disjointness is reasoned in coordinate space, so it holds regardless of layout.
https://github.com/llvm/llvm-project/pull/220244
More information about the Mlir-commits
mailing list