Reductions collapse a vector into a scalar — held, deliberately, in
element 0 of a vector register (any single register, LMUL
ignored), so the loop never round-trips through the scalar core.
The .vs suffix reads “vector op scalar”: vd[0] = op(vs1[0],
vs2[active]).
| Semantics | |
|---|---|
| vredsum / vredmax[u] / vredmin[u] / vredand / vredor / vredxor .vs | Single-width integer reductions; sums wrap on overflow. The scalar operand always participates, masked or not; inactive ELEMENTS are excluded. |
| vwredsumu / vwredsum .vs | Widening sums: zero-/sign-extend SEW elements, sum, add the 2·SEW scalar, produce a 2·SEW scalar — dot-product accumulators without overflow anxiety. |
| vfredosum .vs | ORDERED FP sum: (((vs1[0]+vs2[0])+vs2[1])+…)+vs2[vl−1], each addition with full scalar flag/special semantics. |
| vfredusum .vs | UNORDERED FP sum: any association tree — the fast one (old mnemonic vfredsum aliases here). vfredmax/vfredmin round out the FP set. |
| vfwredosum / vfwredusum .vs | Widening FP sums into a 2·SEW scalar. |
Rules with teeth: destination may overlap sources (even v0); tail = everything past element 0, under the usual vta policy; vl=0 performs nothing — the scalar is not copied to vd (set vl=1 and copy explicitly if you need it); traps report vstart=0 only, and nonzero vstart is illegal — a half-done reduction can’t resume.
Hardware Designer Notes
The reduction network is the one vector structure that isn’t lane-parallel — budget the cross-lane wiring (log depth × SEW width) and keep vfredosum on a separate slow path so its serialization can’t infect the tree.
Minimal Linux-boot hart MUST
- Include the scalar operand unconditionally while excluding inactive elements — two different participation rules in one instruction
- Enforce the vstart=0 requirement (illegal otherwise) and the vl=0 no-write rule
- Make vfredosum genuinely element-ordered with per-step flag semantics — a tree here is non-conformant
MAY simplify / trap-and-emulate
- Tree-reduce everything except vfredosum; a lane-halving log-depth network is the standard structure
- Iterate vfredosum on the scalar-compatible FMA lane — nobody expects it fast, they expect it exact
Check yourself — reductions
1.Why do reductions read and write their scalar in ELEMENT 0 of a vector register instead of an x/f register?
2.vfredosum vs vfredusum — what's the trade?
3.vl=0 on a reduction with vd ≠ vs1. What does vd[0] hold afterward?