[Mlir-commits] [mlir] [mlir][vector] Account for subview offset in gather lowering. (PR #195359)
Lukas Sommer
llvmlistbot at llvm.org
Mon May 4 01:10:43 PDT 2026
================
@@ -134,27 +141,64 @@ struct RemoveStrideFromGatherSource : OpRewritePattern<vector::GatherOp> {
if (stridedLayoutAttr.getStrides()[0] != srcTrailingDim)
return failure();
+ // The result memref's offset is the linearized position of the subview's
+ // first element within the source memref. Bail out on dynamic offsets so
+ // we don't have to materialize them; the conditional-load fallback will
+ // still produce correct code.
+ int64_t subviewOffset = stridedLayoutAttr.getOffset();
+ if (ShapedType::isDynamic(subviewOffset))
+ return failure();
+
// 1. Collapse the input memref so that it's "flat".
SmallVector<ReassociationIndices> reassoc = {{0, 1}};
Value collapsed = memref::CollapseShapeOp::create(
rewriter, op.getLoc(), subview.getSource(), reassoc);
- // 2. Generate new gather indices that will model the
- // strided access.
+ // 2. Generate new gather indices that will model the strided access.
+ // Take `memref<4xf32, strided<[3], offset: 1>>` and lane k as an example.
+ // For the rewrite to be correct, the flat positions must match:
+ // new_off + new_idxs[k] = 1 + (base_off + idxs[k]) * 3
+ // = 1 + base_off * 3 + idxs[k] * 3
+ // So the newIdxs is scaled with the stride.
IntegerAttr stride = rewriter.getIndexAttr(srcTrailingDim);
VectorType vType = op.getIndices().getType();
Value mulCst = arith::ConstantOp::create(
rewriter, op.getLoc(), vType, DenseElementsAttr::get(vType, stride));
-
Value newIdxs =
arith::MulIOp::create(rewriter, op.getLoc(), op.getIndices(), mulCst);
- // 3. Create an updated gather op with the collapsed input memref and the
- // updated indices.
+ // 3. Linearize the gather's base offsets through the source memref. On the
+ // collapsed memref the trailing offset must be scaled by the source's
+ // trailing dim and shifted by the subview's static offset.
+ // Pick new_idxs[k] = idxs[k] * 3 (that's step 2), and solve for new_off:
+ // new_off = 1 + base_off * 3
+ // = subview_offset + base_off * stride
+ SmallVector<Value> newOffsets(op.getOffsets());
+ bool trailingOffsetIsZero = isZeroInteger(newOffsets.back());
+ if (!trailingOffsetIsZero) {
+ Value strideVal =
+ arith::ConstantIndexOp::create(rewriter, op.getLoc(), srcTrailingDim);
+ newOffsets.back() = arith::MulIOp::create(rewriter, op.getLoc(),
+ newOffsets.back(), strideVal);
+ }
+ if (subviewOffset != 0) {
+ Value subviewOffsetValue =
+ arith::ConstantIndexOp::create(rewriter, op.getLoc(), subviewOffset);
+ if (trailingOffsetIsZero) {
+ newOffsets.back() = subviewOffsetValue;
+ } else {
+ newOffsets.back() =
+ arith::AddIOp::create(rewriter, op.getLoc(), newOffsets.back(),
+ subviewOffsetValue)
+ .getResult();
+ }
+ }
----------------
sommerlukas wrote:
Nit/question: Could we simplify the logic here with `createOrFold`? If the trailing offset of the operation is zero, the multiplication with the stride and the addition to the subview offset should fold.
https://github.com/llvm/llvm-project/pull/195359
More information about the Mlir-commits
mailing list