[Mlir-commits] [mlir] [mlir][vector] Fold `in_bounds` for transfers with loop-derived indices (PR #215340)
Matthias Springer
llvmlistbot at llvm.org
Thu Aug 13 10:47:16 PDT 2026
================
@@ -5373,23 +5373,39 @@ VectorType TransferReadOp::getVectorType() {
template <typename TransferOp>
static bool isInBounds(TransferOp op, int64_t resultIdx, int64_t indicesIdx) {
- // TODO: support more aggressive createOrFold on:
- // op.getIndices()[indicesIdx] + vectorType < dim(op.getSource(), indicesIdx)
if (op.getShapedType().isDynamicDim(indicesIdx))
return false;
// Scalable dimensions are `vscale` times larger at runtime, so the static
// size is only a lower bound and cannot prove that the transfer fits.
if (op.getVectorType().getScalableDims()[resultIdx])
return false;
Value index = op.getIndices()[indicesIdx];
- std::optional<int64_t> cstOp = getConstantIntValue(index);
- if (!cstOp.has_value())
- return false;
int64_t sourceSize = op.getShapedType().getDimSize(indicesIdx);
int64_t vectorSize = op.getVectorType().getDimSize(resultIdx);
+ // Largest index at which a full vector still fits. Computed as a subtraction
+ // so that adding to a large index cannot overflow.
+ int64_t maxStart = sourceSize - vectorSize;
+
+ // `in_bounds` guarantees that the transfer, including its starting point,
+ // stays within the source, so a negative index is out of bounds.
+ if (std::optional<int64_t> cstOp = getConstantIntValue(index))
+ return *cstOp >= 0 && *cstOp <= maxStart;
+
+ // The index is typically a loop induction variable or an affine expression
+ // thereof. The transfer is in bounds if even the largest index the enclosing
+ // loops can produce leaves room for a full vector.
+ FailureOr<int64_t> maxIndex = ValueBoundsConstraintSet::computeConstantBound(
+ presburger::BoundType::UB, index, /*stopCondition=*/nullptr,
+ ValueBoundsOptions{/*closedUB=*/true});
+ if (failed(maxIndex) || *maxIndex > maxStart)
+ return false;
- return cstOp.value() + vectorSize <= sourceSize;
+ // The starting point must be in bounds as well. Queried only once the upper
+ // bound holds, so that indices that fail it pay for one query, not two.
+ FailureOr<int64_t> minIndex = ValueBoundsConstraintSet::computeConstantBound(
----------------
matthias-springer wrote:
This is building a constraint set, which can be quite expensive. `isInBounds` is called from the folder and therefore by the canonicalizer pass. This could severely blow up compilation time. The optimization itself makes sense, but I would create a separate pass for it.
https://github.com/llvm/llvm-project/pull/215340
More information about the Mlir-commits
mailing list