[all-commits] [llvm/llvm-project] 0e7fb8: [mlir][vector] Support fixed-size masks in `elimin...

Dhairyashil R G via All-commits all-commits at lists.llvm.org
Fri Sep 25 04:43:37 PDT 2026


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: 0e7fb8bcf11a59d564bf45d0568d528bf1e9bdcf
      https://github.com/llvm/llvm-project/commit/0e7fb8bcf11a59d564bf45d0568d528bf1e9bdcf
  Author: Dhairyashil R G <dhairyashil25 at gmail.com>
  Date:   2026-09-25 (Fri, 25 Sep 2026)

  Changed paths:
    M mlir/include/mlir/Dialect/Vector/Transforms/VectorTransforms.h
    M mlir/lib/Dialect/Vector/Transforms/VectorMaskElimination.cpp
    M mlir/test/Dialect/Vector/eliminate-masks.mlir
    M mlir/test/lib/Dialect/Vector/TestVectorTransforms.cpp

  Log Message:
  -----------
  [mlir][vector] Support fixed-size masks in `eliminateVectorMasks` (#221595)

`eliminateVectorMasks` returned immediately unless a `VscaleRange` was
supplied. The TODO above that early return argued the fixed-size case
was unlikely to be useful, because "for fixed-size code dimensions are
all static so masks tend to fold away".

That is only true when the mask operand is constant. When it comes from
an induction variable, which is what tiling produces, the operand is not
constant and no fold removes the mask, even though value-bounds analysis
can prove it all-true. For example, `-canonicalize` leaves this alone:

```mlir
scf.for %i = %c0 to %c1024 step %c4 {
  %rem = arith.subi %c1024, %i : index
  %mask = vector.create_mask %rem : vector<4xi1>
  %v = vector.transfer_read %t[%i], %f0, %mask : tensor<1024xf32>, vector<4xf32>
  ...
}
```

`%i <= 1020`, so `%rem >= 4` and the mask is all-true.

The algorithm was never scalable-specific; only the bound query was.
This makes `vscaleRange` genuinely optional: without one, the lower
bound is computed with `ValueBoundsConstraintSet::computeConstantBound`
and compared against the mask dimension. Scalable dimensions still need
a range and bail without one, so a fixed-size caller cannot prove a
dimension whose runtime size is `vscale` times the size in the type. The
scalable path is unchanged, and the existing test still passes with its
RUN line untouched.

### Behaviour change for downstream callers

An omitted `vscaleRange` used to make the call a no-op. It now runs the
fixed-size analysis.

No in-tree caller relies on the old meaning, but IREE does call this
unconditionally in `Codegen/Common/GenericVectorization.cpp`, passing
`getDefaultVscaleRange()`, which returns `std::nullopt` for every target
other than AArch64+SVE. For those targets this patch turns a no-op into
live mask elimination. That is the intended benefit, but it is worth
knowing before the next integrate. The added cost is bounded: constant
and `vscale`-multiple operands short-circuit before any analysis, so
only `create_mask` ops with unknown operands pay for a bound query.

### Tests

New `eliminate-masks-fixed-size.mlir`, run through a `fixed-size` option
added to the test pass: two cases that are eliminated (the tiled loop
above, and a dynamic operand bounded by `arith.maxsi`) and three that
are not (an unbounded operand, a lower bound smaller than the mask
dimension, and a scalable dimension with no vscale range). Each negative
was checked to fail for the stated reason, by making the smallest change
that flips it.

Context:
https://discourse.llvm.org/t/rfc-should-vector-transfer-read-write-keep-in-bounds-measurements-on-the-masking-alternative/91649

Assisted-by: Claude



To unsubscribe from these emails, change your notification settings at https://github.com/llvm/llvm-project/settings/notifications


More information about the All-commits mailing list