Phase 2, week 9retrospective

LMUL selection

LMUL groups vector registers; choosing it to fit the accumulator tile avoids spills and wasted vl.


LMUL is a shape, not a size

VLMAX = LMUL * VLEN / SEW. At the rig’s vlen=256 and SEW=32 that is 8 lanes for m1, 16 for m2, 32 for m4 and 64 for m8. One vle32.v at m4 fills 32 floats in a single instruction from a four-register-aligned group, so instruction count per tile falls roughly as 1/LMUL.

The trap runs the other way. VLMAX is the smallest vector operation you can issue, so a column tile narrower than VLMAX leaves lanes idle in every op of the loop. A tile of 8 columns against m4 runs each vfmacc at vl=8 of 32 lanes: the same instruction slot, a quarter of the work.

Alignment narrows the choice

A group starts on a multiple of its LMUL. With v0 reserved for masks, m2 leaves 15 groups, m4 leaves 7, and m8 leaves exactly three, v8, v16 and v24. A double-buffered m8 scheme needs six groups and cannot exist, which is a structural limit rather than a tuning preference.

The rule that follows: match LMUL to the column extent of the accumulator tile. If NR is 16 at vlen=256 in f32, use m2 and keep one group per row. At m1 the same tile is two groups per row, more instructions and the same registers; at m4 the instruction count drops and half of every lane is wasted. Which side of that trade you want is a sweep, not a rule.

The compiler path does not take an LMUL argument: the vector types the vectorizer emits imply it, and vsetvli insertion derives vtype from those types. Confirm the mapping in disassembly rather than in the source.

Things that break

The intrinsics suffix and the vsetvl you called disagree. __riscv_vsetvl_e32m4 followed by __riscv_vfmacc_vv_f32m1 compiles, because they are separate functions, and the compiler repairs the mismatch with an extra vsetvli per call or reinterprets the register. You notice it as a vsetvli between two vfmacc instructions in llvm-objdump -d. The second failure is changing LMUL between the K loop and the epilogue, which toggles vtype and splits the accumulator’s live range at the worst moment.

Sources

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

At VLEN=256 and SEW=32, what is VLMAX for `e32,m4`?

An accumulator tile is 4 rows by 16 columns of f32 at VLEN=256. Which LMUL puts one register group on one row?

Why does `m8` rarely pay off for a small accumulator tile?

0 / 3 correct

← back to the map