31.16V XIV: Permutation — Moves, Slides, Gather, Compress

Part III Linux boot: recommended Vol. I (Unprivileged) pp. 362–368 · ~2 min read

Data movement within the register file — from single-element scalar taps to full crossbar shuffles.

The permutation set (§31.16)
Semantics & rules
vmv.x.s / vmv.s.x — and vfmv.f.s / vfmv.s.fElement 0 ↔ scalar register taps; LMUL ignored.
vslideup .vx/.vivd[i+OFFSET] = vs2[i]; elements below max(vstart, OFFSET) unchanged. Destination may NOT overlap source (WAR hazard + restartability) — reserved otherwise.
vslidedown .vx/.vivd[i] = vs2[i+OFFSET], reading 0 past VLMAX; overlap allowed. Power-of-2 offsets may be fast-pathed.
vslide1up / vslide1down (+ vfslide1up/down)Slide by one AND insert a scalar (x/f) at the vacated end (element 0 for up, vl−1 for down) — the recurrence and sliding-window primitive.
vrgather.vv / vrgatherei16.vv / .vx / .vivd[i] = (index ≥ VLMAX) ? 0 : vs2[index] — the general gather. ei16 fixes index EEW at 16 bits (SEW=8 indices can’t span long vectors; SEW=64 indices waste bits; 16 always suffices since VLMAX ≤ 65536). .vx/.vi broadcast one element. No source overlap.
vcompress.vmPack vs2’s elements selected by mask vs1 densely into vd’s low elements, order preserved. Always unmasked; vstart must be 0; no overlap with either source.
vmv1r.v / vmv2r.v / vmv4r.v / vmv8r.vWhole-register copies (like the whole-register loads: vtype-independent), aligned power-of-2 counts.
Dotted-underlined cells have explanations — click one.

The compaction pattern, closing the loop from the mask page:

    vmslt.vx v0, v8, t0        # select: elements < threshold
    vcompress.vm v16, v8, v0   # pack survivors densely
    vcpop.m  t1, v0            # how many survived
    vsetvli  x0, t1, e32, m1, ta, ma
    vse32.v  v16, (a2)         # store the packed result

Hardware Designer Notes

vrgather throughput is the classic vector-unit differentiator: element-serial (cheap, slow), SEW-grouped banks (middle), or full crossbar (fast, quadratic wiring). Decide by workload — sorting and AI tokenization lean on gathers; scientific kernels mostly don’t.

Minimal Linux-boot hart MUST

  • Enforce the overlap reservations (slideup, gather, compress) and vcompress’s vstart=0 rule
  • Implement vrgather’s out-of-range-reads-zero and the ei16 index decoupling
  • Keep the scalar-tap asymmetry exact: reads fire at vl=0, writes don’t

MAY simplify / trap-and-emulate

  • Implement vrgather iteratively (element per cycle) on narrow datapaths — correct, and honest about the crossbar you didn’t build
  • Fast-path power-of-2 slide offsets and slide1 as dedicated boundary muxes
  • Sequence vcompress with a running-popcount pointer — one pass, no crossbar needed

Check yourself — permutation instructions

1.Why is vslideup's destination forbidden from overlapping its source?

2.What distinguishes vrgather.vv from vrgatherei16.vv, and why does the latter exist?

3.What does vcompress.vm do, and what are its unusual restrictions?

4.Why do vslide1up/vslide1down (and vf variants) exist when vslideup/down cover any offset?

4 questions