Scalable vector lowering
The vector-to-LLVM pipeline must preserve scalable types through translation so the backend emits VLEN-agnostic code.
Brackets are the contract
MLIR marks a scalable dimension with square brackets: vector<[2]xf32>. Translation prints it as <vscale x 2 x float>, and the backend then chooses LMUL and VL from VLEN. The guarantee is not speed. It is that the IR never mentions VLEN, so the same object file is correct at 128, 256 and 512 bits.
Order the pipeline and then check its output:
mlir-opt vec.mlir --convert-vector-to-llvm ... \
| mlir-translate --mlir-to-llvmir > vec.ll
grep -c 'vscale x' vec.ll
Zero matches means the path produced fixed vectors. That is the exact failure this stage exists to prevent, and it is silent: the binary runs, the answer is right, and the loop uses a constant AVL with lanes left idle above it.
Masks and lengths are two different things
A masked transfer needs a mask operand in the IR. vector.mask wrapping a transfer is one route; at LLVM level the forms are llvm.masked.load and llvm.masked.store, which carry the mask and leave the length to the backend, and llvm.vp.load and llvm.vp.store, which carry an explicit vector length. On RISC-V the length-carrying form is what lets the AVL become a runtime vl while the mask covers the ragged edge. Take the length away and the backend must pick one, usually VLMAX, so every iteration configures a vector length larger than the work it has.
Shapes constrain the vectorizer. vector.shape_cast between fixed and scalable vectors has no general lowering, and a non-trailing scalable dimension has no LLVM form. Confirm the mask op and the VP intrinsic names against the release you pinned; both have moved recently.
Things that break
mlir-translate fails on an operation the conversion did not legalize, and you find out only after a long pipeline. Grep the .ll for vector. first. The subtler failure translates cleanly, passes the grep, and still runs scalarly because the transfer was lowered to a loop of scalar loads: the disassembly shows flw and fsw where vle32.v belongs.
Sources
- LLVM RISC-V Vector Extension guidedocs · LLVM 23
- MLIR vector dialectdocs · LLVM 23
- LLVM vector predication proposaldocs
A version records the documentation the claim was checked against, not a house pin. Confirm flags with --help on the release you installed.
Check yourself
You translate the module and `grep -c "vscale x" vec.ll` prints 0. What happened?
Which vector shape cannot be converted to LLVM at all?
What does `llvm.vp.load` carry that `llvm.masked.load` does not?