Chaining was not invented for textbooks. Describing the Cray-1 (1976), Richard Russell of Cray Research wrote in 1978 that chaining lets the machine "generate interim results and use them again immediately without additional memory references" — and that its memory "is organized in 16 banks", a detail that comes back in the last section.
VMIPS and the art of counting convoys: chaining, lanes, lengths, masks and banks
After this lesson you will pack any vector program of the papers into convoys and give its clock cycles with the table or the timeline the paper asks for — and explain what lanes, the vector-length register, strip mining, the mask register and memory banks change, and what each of them costs.
Question 6 of the quiz block of the 22 June 2026 paper describes a vector processor with registers of 16 elements and three vector units — one load/store unit, one add/subtract unit, one multiply/divide unit, each "with operation chaining" — and gives it seven lines of code: two vector loads, three arithmetic instructions, two vector stores. "How many convoys? How many clock cycles to execute the code?" Answer 1: 2 convoys, 32 cycles. Answer 2: 3 convoys, 48. Answer 3: 4 convoys, 64. Answer 4: 5 convoys, 80.
The July 2024 paper asked the same question on the same code, and every paper since has one like it. Three of the four answers are wrong, and each is what one particular slip produces. The unit that decides the right one does no arithmetic at all — and the same unit, with the memory behind it, decides how fast a vector machine can walk down a column of a matrix.
Convoys and chimes: time counted in whole vectors
Lesson 30 built VMIPS: the scalar MIPS pipeline plus a vector unit — vector registers of 64 elements of 64 bits, deeply pipelined vector functional units, one vector load/store unit — so that DAXPY, \(Y = a \cdot X + Y\) on 64 elements, takes 6 instructions instead of about 578 (p. 402). Here you count its clock cycles. These are its five vector instructions as the papers write them; F0 already holds the scalar a.
L.V V1, RX # V1 ← X
MULVS.D V2, V1, F0 # V2 ← a * X
L.V V3, RY # V3 ← Y
ADDVV.D V4, V2, V3 # V4 ← a * X + Y
S.V V4, RY # Y ← V4
A vector unit is a deep pipeline that accepts one new element per clock cycle. MULVS.D on 64 elements keeps the multiplier busy for 64 cycles, plus a few cycles while the first element travels down the pipeline — a start-up that the papers' counts leave out. Picture each unit as a car-wash tunnel: a vector instruction sends a train of 64 cars through it, one car per cycle. The whole question is which trains may roll at the same time.
Convoy — a set of vector instructions that execute together, each on its own functional unit. Two rules: at most one instruction per unit in a convoy (and the load/store unit is a unit), and an instruction that needs a vector produced inside the same convoy may join it only if the machine has chaining.
Chime — the time one convoy takes: VL clock cycles when every unit handles one element per cycle. A sequence packed into m convoys runs in m chimes.
- \(m\)
- number of convoys of the sequence
- \(\mathrm{VL}\)
- vector length: elements per vector register — 64 on VMIPS, 16 or 8 on the papers' machines
- \(T\)
- execution time with one element per cycle per unit (one lane), start-up ignored
Now the dependences. MULVS.D needs V1, which L.V is still filling. Without chaining, the multiply waits until the load has written the whole of V1 — the last of its 64 elements — so the two cannot share a convoy. With chaining, the first element of V1 goes from the load unit straight into the multiplier, the way forwarding passes a result to the next instruction in the five-stage pipeline. The multiply trails the load by a few cycles, element by element, inside the same chime: chaining is forwarding for vectors.
Before: no chaining — 4 chimes, 256 cycles
After: chaining — 3 chimes, 192 cycles
Without chaining every true dependence ends a convoy: the multiply comes after the first load, the add after the multiply, the store after the add — four convoys, 4 × 64 = 256 cycles. With chaining the multiply joins the first load and the add joins the second load: three convoys, 3 × 64 = 192 cycles. The store would chain on the add too, but the load/store unit is busy with L.V V3 in that convoy. The paper asks for the same result as a table, one row per convoy and one column per unit:
| Load/Store Vector Unit | Mul/Div Vector Unit | Add/Sub Vector Unit | |
|---|---|---|---|
| 1^ convoy | L.V V1, RX | MULVS.D V2, V1, F0chained | |
| 2^ convoy | L.V V3, RY | ADDVV.D V4, V2, V3chained | |
| 3^ convoy | S.V V4, RY |
| Load/Store Vector Unit | Mul/Div Vector Unit | Add/Sub Vector Unit | |
|---|---|---|---|
| 1^ convoy | L.V V1, RX | ||
| 2^ convoy | L.V V3, RY | MULVS.D V2, V1, F0 | |
| 3^ convoy | ADDVV.D V4, V2, V3 | ||
| 4^ convoy | S.V V4, RY |
With chaining, only the structural rule — one instruction per unit — separates convoys; without it, every true dependence does too.
The quiz of every paper, in four moves
The three official papers (July 2024, June 2025, June 2026) each have a convoy quiz worth 1 point, plus 1 for the table or timeline that motivates it, on a machine described in the same words: a vector register file of "32 vectors of 16 elements" (or of 8) "per 64 bits/element", "One Load/Store Vector Unit with operation chaining and memory bandwidth 64 bits", one ADD/SUB and one MUL/DIV unit, both with chaining. The February 2025 and January 2026 papers transcribed in the notes have a quiz of the same kind. Four moves solve it.
- Read the chime. VL is the number of elements per register, 16 or 8. A memory bandwidth of 64 bits moves one 64-bit element per cycle, and so does every arithmetic unit: a convoy lasts VL cycles.
- Find the floor. Count the instructions of each unit. The busiest unit needs at least that many convoys. On every paper's machine it is the single load/store unit, so the number of vector loads and stores is a lower bound on m.
- Pack. Put each instruction into the earliest convoy where its unit is still free and each source vector is either complete — written in an earlier convoy — or produced in the same convoy by an instruction it chains to. An instruction does not wait for unrelated instructions above it in the listing.
- Multiply and draw. Cycles = m × VL. Then fill the paper's table (one row per convoy, one column per unit) or its timeline (one strip of VL cycles per convoy).
Move 3 is the counting of the notes' solutions and of every table in this lesson: an independent instruction may run ahead of unrelated ones above it. In the June 2025 quiz the first multiply joins the first load, although two more loads stand between them in the listing; move 2 then explains why that quiz cannot go below four convoys.
Know the other reading too. A vector unit that issues strictly in listing order cannot start that multiply before the third load, and packing that way gives the June 2025 code 6 convoys, 48 cycles; on the other papers' code both readings give the same count. No official key settles it, so write the assumption in one line under your table. Try the moves yourself before reading the solutions below.
Now the longest quiz, from the February 2025 paper (transcribed in the notes, p. 580): nine instructions on registers of 8 elements, same machine.
L.V V1, RA
L.V V3, RB
MULVS.D V1, V1, F0
ADDVV.D V2, V1, V1
MULVS.D V2, V2, F0
ADDVV.D V3, V2, V3
S.V V1, RX
S.V V2, RY
S.V V3, RZ
Move 2 gives the answer before any table: two loads and three stores on one load/store unit need at least 5 convoys. Move 3 shows that five are enough, so the answer is 5 convoys; 5 × 8 = 40 clock cycles — Answer 4, as the notes say.
| Load/Store Vector Unit | Mul/Div Vector Unit | Add/Sub Vector Unit | |
|---|---|---|---|
| 1^ convoy | L.V V1, RA | MULVS.D V1, V1, F0chained | ADDVV.D V2, V1, V1chained |
| 2^ convoy | L.V V3, RB | MULVS.D V2, V2, F0 | ADDVV.D V3, V2, V3chained |
| 3^ convoy | S.V V1, RX | ||
| 4^ convoy | S.V V2, RY | ||
| 5^ convoy | S.V V3, RZ |
| Load/Store Vector Unit | Mul/Div Vector Unit | Add/Sub Vector Unit | |
|---|---|---|---|
| 1^ convoy | L.V V1, RA | ||
| 2^ convoy | L.V V3, RB | MULVS.D V1, V1, F0 | |
| 3^ convoy | S.V V1, RX | ADDVV.D V2, V1, V1 | |
| 4^ convoy | MULVS.D V2, V2, F0 | ||
| 5^ convoy | S.V V2, RY | ADDVV.D V3, V2, V3 | |
| 6^ convoy | S.V V3, RZ |
In the first convoy the load feeds the multiply, which feeds the add: a chain of three. In the second, MULVS.D V2 reads the V2 that the first convoy completed, and ADDVV.D V3 chains on two producers at once, the multiply and the load of V3. The notes' own table puts S.V V1 before the second load — also legal, since V1 is complete after the first convoy — with the same count. Without chaining every true dependence costs a convoy, and the chain L.V V1 → MULVS.D V1 → ADDVV.D V2 → MULVS.D V2 → ADDVV.D V3 → S.V V3 has six links: 6 convoys, 48 cycles.
Why 8 cycles per convoy? The notes never say. Each register holds 8 elements of 64 bits; the load/store unit moves 64 bits — one element — per cycle, and so does every arithmetic unit; the start-up of the pipelines is not counted. A convoy is therefore a chime of 8 cycles, and every option of the quiz is a multiple of 8: 16, 24, 32, 40, 48.
"Chaining puts dependent instructions together, so with chaining everything fits in one or two convoys." No: chaining removes the data constraint only. The structural one — one instruction per unit per convoy — stays, and on the papers' machines it is the one that sets the count: the load/store unit works in every convoy of every chained solution above.
Lanes: several elements per cycle, the same instructions
So far a unit handled one element per cycle, and a chime lasted VL cycles. Hardware can do better without touching the program: it replicates each pipeline into L lanes. Take ADDVV.D V3, V1, V2 on 16 elements. With one lane, element 0 enters the adder in the first cycle and element 15 in the sixteenth. With four lanes, four adders take elements 0 to 3 in the first cycle and 4 to 7 in the second: the vector is through in 4 cycles.
Before: one lane — one element per cycle
After: four lanes — four elements per cycle
ADDVV.D on 16 elements; the numbers in the cells are element indices. Before: one lane, 16 cycles. After: element i goes to lane i mod 4 — lane 1 handles elements 1, 5, 9 and 13 — and the vector takes ⌈16/4⌉ = 4 cycles. The instruction did not change.The interleaving of Fig. 2 holds for every register: element i lives in lane i mod L, so an element-wise operation never needs data from another lane, and the lanes need no wires between them. Each lane is a slice of the register file plus one pipeline of each unit (p. 405; the notes' Figure 30, p. 392, draws elements 0, 4, … 60 in the first of four lanes). With L lanes a vector of n elements takes ⌈n / L⌉ cycles (p. 405), and the chime model becomes:
- \(L\)
- number of lanes; element i of every register lives in lane \(i \bmod L\)
- \(m,\ \mathrm{VL}\)
- convoys and vector length, as before
The notes' Example 3 is DAXPY with VL = 64: the multiply takes 64 cycles on one lane and 16 on four, the add likewise (p. 405). Chained, the three convoys take 3 × 16 = 48 cycles instead of 192.
The instruction set does not change: the same ADDVV.D runs on one lane or on eight, and the same binary gets faster — the notes say vector machines scale "transparently" with hardware width, unlike scalar unrolling (p. 406), which rewrites the code for every width. The cost is paid elsewhere: the register file needs read and write ports for every lane, and the load/store unit must deliver L words per cycle. Where those words come from is the subject of the last section.
Lanes divide the chime, not the number of convoys: T ≈ m × ⌈VL/L⌉.
Longer than a register: MVL, VLR and strip mining
A loop rarely has exactly 64 iterations. Take n = 100 on VMIPS, whose registers hold 64 elements. The first pass handles elements 0 to 63. If every vector instruction always processed a whole register, the second pass would touch elements 64 to 127: 28 elements past the end of the arrays, read and written by mistake (pp. 407–408). One register fixes it.
Maximum vector length (MVL) — the number of elements a vector register can hold: a hardware constant, 64 on VMIPS, 32 on the machine of the June 2026 quiz.
Vector-length register (VLR) — a control register that tells every vector instruction how many elements to process: \(0 \le \mathrm{VLR} \le \mathrm{MVL}\) (eq. 83).
The second pass therefore sets VLR = 36 and processes elements 64 to 99; the other 28 entries of the register are simply not used. MVL is the hardware; VLR is the knob the software turns.
When n is larger than MVL the compiler applies strip mining: it cuts the loop into strips of at most MVL elements — ⌊n / MVL⌋ full strips and, when n mod MVL is not zero, one short strip with VLR = n mod MVL (eq. 84, p. 408). The notes' example: 1000 = 15 × 64 + 40.
- \(n\)
- trip count of the loop
- \(\mathrm{MVL}\)
- maximum vector length of the machine
Two papers ask it as a quiz: for (i=0; i<260; i++) Y[i] = X[i] + Y[i]; on VMIPS with "8 registers of 64 elements" (July 2024) or "16 Vector registers of 32 elements" (June 2026) — which transformation: trace scheduling, software pipelining, strip mining or a mask register? Strip mining: 260 = 4 × 64 + 4, or 260 = 8 × 32 + 4. Trace scheduling and software pipelining are compiler techniques that reorder scalar instructions for a VLIW (lesson 21 meets this very quiz from their side), and a mask register is for an if inside the loop, which this loop does not have. The number of registers is not the problem either: the loop needs two.
Hennessy and Patterson write the strip-mined loop with the short strip first; the notes put it last. Both are correct:
low = 0;
VL = n % MVL; /* odd-size strip first */
for (j = 0; j <= n / MVL; j++) { /* one pass per strip */
for (i = low; i < low + VL; i++)
Y[i] = a * X[i] + Y[i]; /* vector code, VLR = VL */
low = low + VL;
VL = MVL; /* later strips are full */
}
The inner loop becomes one sequence of vector instructions, executed once per strip with VLR set to VL. The price is the scalar strip loop around them, a few instructions per strip that the papers' counts ignore.
An if inside the loop: the vector mask register
Now a loop that is parallel but not uniform (p. 409):
for (i = 0; i < 64; i++)
if (X[i] != 0)
X[i] = X[i] - Y[i];
Every iteration is independent, yet a single SUBVV.D would subtract at every element, including those the if skips. A vector processor has one program counter for all 64 elements: there is nothing to branch around element by element. Instead it turns the condition into data.
Vector mask register (VM in Hennessy & Patterson, VMR in the notes) — a register of MVL bits, one per element. A vector compare sets bit i when the condition holds for element i; while masking is on, every vector instruction writes only the elements whose bit is 1 and leaves the others unchanged — predication at the level of vectors.
In Hennessy and Patterson's VMIPS, written with the papers' load and store, the loop becomes (F0 holds 0.0):
L.V V1, RX # V1 ← X
L.V V2, RY # V2 ← Y
SNEVS.D V1, F0 # VM(i) = 1 if V1(i) != F0
SUBVV.D V1, V1, V2 # subtract under the mask
S.V V1, RX # X ← V1
SUBVV.D then updates the 10 elements with VM = 1 (blue) and leaves the 6 crossed ones untouched. The subtracter still spends a cycle on each of the 16.The mask keeps the loop vectorizable, with no scalar fallback, and works with any vector instruction (p. 409). What it does not do is save time: SUBVV.D still streams all 64 elements through the subtracter, masked or not, so it takes the same 64 cycles. In Fig. 3, 6 of the 16 cycles do no useful work; the more elements are masked off, the lower the efficiency — still better than running the loop as scalar code (p. 410). Lesson 32 meets the same price under another name, branch divergence on a GPU.
A mask preserves vectorizability, not speed: a masked element still costs its cycle.
Memory banks: when the stride keeps hitting the same bank
A load/store unit that delivers one 64-bit word per cycle needs a memory that can keep up, and one memory bank cannot: after an access it stays busy for several cycles. Vector machines therefore spread consecutive words over many memory banks, round-robin (p. 411):
With 8 banks, words 0 to 7 sit in banks 0 to 7 and word 8 in bank 0 again. Walk a row of a C matrix — consecutive words, stride 1 — and every bank serves one element and is not asked again for eight cycles. Now walk a column of a matrix whose rows hold 128 words: consecutive elements are 128 words apart, and 128 mod 8 = 0, so every element lands in the same bank (p. 412). The notes' picture is a supermarket with eight checkouts and eight shoppers all queuing at checkout 0, while seven cashiers wait.
Before: rows of 128 words — stride 128
After: rows padded to 129 words — stride 129
The number of different banks a strided access visits is (p. 412):
- stride
- distance in words between consecutive elements: 1 along a row of a C matrix, the row length down a column (the notes'
LVWS V1, (R1, R2)loads V1 from base R1 with stride R2) - gcd
- greatest common divisor
Stride 1 and every odd stride visit all 8 banks; stride 2 visits 4; stride 4, two; strides 8, 32 and 128 visit one. Whether that costs time depends on how long a bank stays busy. Hennessy and Patterson's example, not in the notes: 8 banks, a bank busy time of 6 cycles, a memory latency of 12, a 64-element load. With stride 1 each bank is reached again only after 8 elements, when its 6 busy cycles are over: 12 + 64 = 76 cycles. With stride 32 every access waits for the one bank: 12 + 1 + 6 × 63 = 391 cycles, five times slower. The steps below show where the gcd comes from, and when a repeated bank hurts:
Element k of an access with stride s, starting at word address \(a_0\), lies at \(a_0 + k s\); with N banks its bank is
\[ b_k = (a_0 + k\,s) \bmod N . \]Elements k and k + d fall in the same bank exactly when the extra distance d·s is a multiple of N:
\[ d\,s \equiv 0 \pmod{N} . \]Write \(g = \gcd(s, N)\), so \(s = g s'\) and \(N = g N'\) with s′ and N′ coprime. Dividing by g, d·s′ must be a multiple of N′; since s′ shares no factor with N′, d itself must be one, and the smallest such d is
\[ d = N' = \frac{N}{\gcd(s, N)} . \]So the banks repeat with period N / gcd(s, N): the first N / gcd(s, N) elements all fall in different banks, and the access visits exactly that many — formula (86).
At one access per cycle the same bank is hit again every N / gcd(s, N) cycles, but it is free only after its busy time t. The access stalls exactly when the bank comes back too soon:
\[ \frac{N}{\gcd(s, N)} \lt t . \]8 banks and t = 6: stride 1 gives 8 ≥ 6, no stall (76 cycles); stride 4 gives 2 < 6, a wait every second element (200 cycles); stride 32 gives 1 < 6, a wait at every element (391 cycles).
The notes list three fixes (pp. 412–413). Change the traversal order, so that the inner loop walks along rows — the loop interchange of lesson 25, met there for caches. Pad each row with one unused word: the column stride becomes 129, gcd(129, 8) = 1, and the column spreads over all eight banks, as in Fig. 4. Or store the matrix column by column (Fortran, MATLAB) when columns are what the code walks. With a power-of-two number of banks every odd stride is harmless (given at least as many banks as busy cycles), while more banks of the same kind do not help a stride that is a multiple of their number: 16 banks and stride 128 still give one bank.
Sparse data have no stride at all. A gather loads a vector from the addresses given by an index vector and a scatter stores to them (p. 413) — LVI and SVI in Hennessy and Patterson's VMIPS. They keep sparse matrices vectorizable, at a cost: every element is a separate access, free to collide with the others.
Back to the quiz of the hook. The unit that decides is the load/store unit. The seven lines contain four memory instructions, and one load/store unit takes one of them per convoy: at least four convoys, so Answers 1 and 2 are impossible on sight. Four are enough — L.V V1 with ADDVS.D V2 and MULVS.D V2 chained behind it, L.V V3 with its add, then one store per convoy. Answer 4, 5 convoys and 80 cycles, is the count without chaining. Answer 3 is right: 4 × 16 = 64 clock cycles. And this section showed why that unit matters twice: its one word per cycle is itself a promise that only the banks can keep. A vector processor is as fast as its memory lets it be.
Exam-style questions
Consider a vector processor architecture, as VMIPS shown in the figure (main memory, vector load/store unit, vector registers, scalar registers, and the FP add/subtract, FP multiply, FP divide, integer and logical vector units).
Present the main concepts. Present the main advantages of vector execution with respect to scalar execution, detailing the features of the vector architecture that provide the advantage.
Show model answer
Main concepts. A vector processor is a SIMD machine: one instruction operates on whole vectors held in vector registers. VMIPS is the scalar MIPS pipeline plus a vector unit: (1) a vector register file — 8 registers of 64 elements of 64 bits, with many read and write ports (16 and 8) through a crossbar — a compiler-controlled buffer between memory and the functional units; (2) deeply pipelined vector functional units (FP add/subtract, FP multiply, FP divide, integer, logical) that deliver one result per cycle after a start-up latency; (3) a vector load/store unit that streams one word per cycle from interleaved memory banks, with unit-stride, strided (LVWS) and indexed (gather/scatter) accesses; (4) scalar registers for addresses, strides and the scalar operands of instructions such as MULVS.D; (5) the vector-length register VLR (0 ≤ VLR ≤ MVL), used with strip mining for loops of any length, and the vector mask register for loops with an IF. Execution time is counted in convoys — instructions that run together, one per unit, dependent ones only with chaining — and chimes of about VL cycles: T ≈ convoys × VL.
Advantages and the feature that provides each. (a) Far fewer instructions fetched, decoded and issued: one vector instruction does the work of a whole loop (DAXPY on 64 elements: 6 instructions instead of about 578) — vector registers and vector instructions; less instruction bandwidth and energy. (b) Almost no loop overhead: index updates and loop branches disappear, one branch per strip of up to MVL elements instead of one per element, hence far fewer control hazards and mispredictions — vector-length semantics, VLR and strip mining. (c) Deep pipelines without stalls: the elements of a vector are independent, so no hazard checks inside an instruction, and dependences between vector instructions are checked once per vector, not once per element — pipelined vector units. (d) Overlap of dependent operations and of several units: chaining forwards element by element and several units run in one convoy (DAXPY in 3 chimes, 192 cycles, instead of 4 chimes, 256) — multiple units plus chaining. (e) Memory latency paid once per vector and a sustained bandwidth of one word per cycle: known access patterns let the load/store unit stream from interleaved banks, with little or no data cache — vector load/store unit plus banks. (f) Scalability without changing the code: L lanes process L elements per cycle, ⌈VL/L⌉ cycles per chime, same instructions. Limits: the gain needs data-level parallelism; masked elements still cost cycles; bad strides cause bank conflicts.
This is Question 2 of the February 2025 paper (notes, p. 578); lesson 30 redraws its VMIPS figure. The question has two halves: answer both. For the concepts, name the parts of the figure and what each does; for the advantages, tie each one to the feature that delivers it — "fewer instructions, because one vector instruction encodes a whole loop" — with a number where you have one (6 against 578 instructions, 192 against 256 cycles). One line on the limits shows that you know where vectors stop helping.
Explain the main concepts and benefits of each one of the following techniques used by vector processors: (1) Chaining; (2) Multiple lanes; (3) Vector length register and strip mining; (4) Vector mask registers; (5) Interleaved memory banks and strided accesses.
Show model answer
(1) Chaining: the result of a vector unit is forwarded element by element to the next unit, so a dependent vector instruction starts as soon as the first element of its operand is produced, instead of waiting until the whole vector is written back. Benefit: dependent instructions run overlapped in the same convoy, one chime instead of two per dependence (DAXPY: 4 convoys, 256 cycles → 3 convoys, 192 cycles). It is the vector analogue of forwarding; it does not remove structural hazards — one instruction per unit per convoy.
(2) Multiple lanes: each vector unit and the vector register file are split into L lanes; element i of every register lives in lane i mod L, so element-wise operations never cross lanes. Benefit: L elements per cycle, a chime of ⌈VL/L⌉ cycles (64 elements on 4 lanes: 16 cycles), with no change to the ISA or the code. Cost: register-file ports and memory bandwidth grow with L.
(3) VLR and strip mining: MVL is the hardware length of a vector register; the vector length register (0 ≤ VLR ≤ MVL) tells each instruction how many elements to process. Strip mining is the compiler transformation that cuts a loop of n iterations into ⌈n/MVL⌉ strips, the short one with VLR = n mod MVL (260 elements on MVL 64: 4 × 64 + 4). Benefit: one vector loop for any n, no access past the end of the arrays. Cost: a scalar strip loop with its overhead.
(4) Vector mask registers: one bit per element, set by a vector compare; instructions executed under the mask update only the elements whose bit is 1. Benefit: loops with an IF stay vectorizable (predication at vector level), no scalar fallback, any instruction can be masked. Cost: masked elements still take their cycle, so efficiency equals the fraction of active elements.
(5) Interleaved banks: consecutive words go to consecutive banks (bank = (address / word size) mod #banks), so a unit-stride access finds a free bank every cycle and the load/store unit sustains one word per cycle; strided loads (LVWS) and gather/scatter through index vectors handle matrix columns and sparse data. A stride visits #banks / gcd(stride, #banks) banks; if that is less than the bank busy time, accesses stall (8 banks, busy time 6, latency 12, 64 elements: stride 128 hits one bank and takes 391 cycles instead of 76). Fixes: pad rows (129 words), interchange the loops, choose a column-major layout.
The June 2026 paper asked eight such sub-points in one 8-point question, about five lines each; the 2024 and 2025 papers had 5-point open questions. A complete sub-point says what the mechanism does, what it buys — with a number — and what it costs.
Let's consider the following code executed by a Vector Processor with: Vector Register File composed of 32 vectors of 16 elements per 64 bits/element; Scalar FP Register File composed of 32 registers of 64 bits; One Load/Store Vector Unit with operation chaining and memory bandwidth 64 bits; One ADD/SUB Vector Unit with operation chaining; One MUL/DIV Vector Unit with operation chaining.
L.V V1, R1 # Load vector from mem. addr. R1 into V1
L.V V3, R2 # Load vector from mem. addr. R2 into V3
ADDVS.D V2, V1, S1 # FP add vector V1 to scalar S1
MULVS.D V2, V2, S2 # FP multiply vector V2 to scalar S2
ADDVS.D V3, V3, S3 # FP add vector V3 to scalar S3
S.V V2, R1 # Store vector V2 into memory addr. R1
S.V V3, R2 # Store vector V3 into memory addr. R2
How many convoys? How many clock cycles to execute the code? Motivate your answer by completing the timing scheme (0, 1, … 15 for the first convoy).
Show model answer
Answer 3: 4 convoys; 64 clock cycles. Four memory instructions on one load/store unit need at least four convoys, and four are enough. A convoy lasts 16 cycles: 16 elements, one 64-bit element per cycle (bandwidth 64 bits), start-up ignored.
| first | instructions of the convoy | last | |
|---|---|---|---|
| 0 | 1 | … L.V V1, R1 · ADDVS.D V2, V1, S1 (chained) · MULVS.D V2, V2, S2 (chained) … | 15 |
| 16 | 17 | … L.V V3, R2 · ADDVS.D V3, V3, S3 (chained) … | 31 |
| 32 | 33 | … S.V V2, R1 … | 47 |
| 48 | 49 | … S.V V3, R2 … | 63 |
The same question was Question 6 of July 2024, with the options 3/48, 2/32 and 4/64. The motivation point is the scheme: four strips of 16 cycles. Say why the count cannot be lower — four memory instructions, one load/store unit — and why chaining matters: without it, 5 convoys and 80 cycles. Swapping the second and third convoy (S.V V2 before L.V V3) is equally correct, and so is the scheme packed strictly in listing order: L.V V1 alone in the first strip, then L.V V3 + ADDVS.D V2 + MULVS.D V2, then ADDVS.D V3 + S.V V2, then S.V V3 — the same 4 convoys.
Let's consider the following code executed by a Vector Processor with: Vector Register File composed of 32 vectors of 8 elements per 64 bits/element; Scalar FP Register File composed of 32 registers of 64 bits; One Load/Store Vector Unit with operation chaining and memory bandwidth 64 bits; One ADD/SUB Vector Unit with operation chaining; One MUL/DIV Vector Unit with operation chaining.
L.V V1, RA
L.V V2, RB
L.V V3, RC
MULVS.D V1, V1, F1
MULVS.D V2, V2, F2
MULVS.D V3, V3, F3
ADDVV.D V2, V2, V1
ADDVV.D V3, V2, V3
S.V V3, RD
How many convoys? How many clock cycles to execute the code? Motivate your answer by completing the table (Load/Store Vector Unit, Mul/Div Vector Unit, Add/Sub Vector Unit; 1^ convoy: L.V V1, RA).
Show model answer
Answer 3: 4 convoys; 4 × 8 = 32 clock cycles (8 elements, one 64-bit element per cycle).
| Load/Store Vector Unit | Mul/Div Vector Unit | Add/Sub Vector Unit | |
|---|---|---|---|
| 1^ convoy | L.V V1, RA | MULVS.D V1, V1, F1 | |
| 2^ convoy | L.V V2, RB | MULVS.D V2, V2, F2 | ADDVV.D V2, V2, V1 |
| 3^ convoy | L.V V3, RC | MULVS.D V3, V3, F3 | ADDVV.D V3, V2, V3 |
| 4^ convoy | S.V V3, RD | ||
| 5^ convoy | |||
| 6^ convoy |
The single load/store unit serialises the three loads and the store; with chaining each multiply joins the convoy of its load, and each add the convoy of its multiply, its other operand being complete (V1 after the 1^ convoy, V2 after the 2^).
The paper fills in L.V V1, RA and leaves six rows: two stay empty here. MULVS.D V1 joins the first convoy although two loads stand before it in the listing, because it does not depend on them — the packing of move 3. Answer 5, 6 convoys and 48 cycles, is the count without chaining and also the count of a packing that keeps strict listing order. No official key exists for this paper: under the table, write the one-line assumption that independent instructions are grouped regardless of listing order.
Let's consider the following code: for (i=0; i<260; i++) Y[i] = X[i] + Y[i]; Which code transformation can be applied to be executed by the VMIPS processor with a Vector Register File composed of 8 registers of 64 elements and 64 bits/element? Motivate your answer.
Show model answer
Strip mining. MVL = 64 < n = 260, so the loop is split into ⌈260/64⌉ = 5 strips: four strips of 64 elements and one of 260 mod 64 = 4 elements (first, in Hennessy and Patterson's code, or last), setting VLR before each strip. Each strip executes L.V V1, RX; L.V V2, RY; ADDVV.D V3, V1, V2; S.V V3, RY. A mask register is for an IF inside the loop, which is absent; trace scheduling and software pipelining are VLIW compiler techniques for scheduling scalar instructions.
Question 5 of July 2024; June 2026 asked it again with 16 registers of 32 elements (260 = 8 × 32 + 4). The motivation point is the arithmetic, plus one sentence on why each distractor does not fit.
Let's consider the following code executed by a Vector Processor with: Vector Register File composed of 32 vectors of 16 elements per 32 bits/element; Scalar FP Register File composed of 32 registers of 32 bits; One Load/Store Vector Unit with memory bandwidth 32 bits; One Add/Sub Vector Unit; One Mul/Div Vector Unit. None of the three units has operation chaining.
L.V V1, RX
ADDVS.D V1, V1, F0
MULV.D V2, V1, V1
DIVVS.D V2, V2, F0
L.V V3, RY
ADDVV.D V3, V2, V3
S.V V2, RZ
S.V V3, RW
How many clock cycles does the code take?
Show model answer
Without chaining every true dependence ends a convoy, and the chain L.V V1 → ADDVS.D V1 → MULV.D V2 → DIVVS.D V2 → ADDVV.D V3 → S.V V3 has six instructions: 6 convoys. A convoy lasts 16 cycles (16 elements, one 32-bit element per cycle): 6 × 16 = 96 clock cycles.
| Load/Store Vector Unit | Mul/Div Vector Unit | Add/Sub Vector Unit | |
|---|---|---|---|
| 1^ convoy | L.V V1, RX | ||
| 2^ convoy | L.V V3, RY | ADDVS.D V1, V1, F0 | |
| 3^ convoy | MULV.D V2, V1, V1 | ||
| 4^ convoy | DIVVS.D V2, V2, F0 | ||
| 5^ convoy | S.V V2, RZ | ADDVV.D V3, V2, V3 | |
| 6^ convoy | S.V V3, RW |
With chaining, as in the January 2026 paper: 4 convoys, 64 cycles — L.V V1 + ADDVS.D + MULV.D; L.V V3 + DIVVS.D + ADDVV.D; S.V V2; S.V V3.
The code is the January 2026 quiz (notes, p. 501) with chaining removed. Without chaining the floor from the load/store unit (4) is not the answer: the chain of six dependent instructions is longer. Note that the elements are 32 bits here and the bandwidth 32 bits: still one element per cycle.
A vector processor has MVL = 64, 4 lanes, one Load/Store Vector Unit that moves 4 elements per cycle, one MUL/DIV and one ADD/SUB Vector Unit, all with operation chaining. The DAXPY loop Y[i] = a * X[i] + Y[i] runs on n = 1000 elements with strip mining; each strip executes L.V, MULVS.D, L.V, ADDVV.D, S.V. Ignoring start-up and the scalar loop overhead, how many clock cycles does the loop take?
Show model answer
Each strip: 3 convoys (L.V + MULVS.D; L.V + ADDVV.D; S.V). Strips: ⌈1000/64⌉ = 16 — 15 of 64 elements and one of 1000 mod 64 = 40. With 4 lanes a chime takes ⌈VL/4⌉ cycles: 16 for a full strip, 10 for the short one.
\[ T = 15 \times 3 \times 16 + 3 \times 10 \] \[ T = 720 + 30 = 750 \]750 clock cycles, 0.75 per element.
Two traps: forgetting the short strip (15 × 48 = 720) and charging it a full chime (16 × 48 = 768). Lanes divide the chime, strips multiply the convoys.
Check yourself
VMIPS with one lane runs a sequence packed into 3 convoys on vectors of 64 elements. How long is a chime, and how long is the sequence?
The July 2024 / June 2026 code needs 4 convoys with chaining. Which changes would reduce the number of convoys? Select all that apply.
With chaining on, only the busiest unit matters: change its load of work, and the count changes.
A vector unit with 4 lanes executes ADDVV.D V3, V1, V2 on 64 elements. Which lane computes element 13, and how many cycles does the instruction take, start-up ignored?
A loop of 200 iterations runs on a vector machine with MVL = 64. How many strips, and what is VLR in the short one?
SUBVV.D V1, V1, V2 runs under a mask with 16 of its 64 bits set, on one lane. How long does it take in the chime model, and what happens to the 48 masked elements?
A matrix of 64-bit words is stored by rows, 128 words per row, in a memory of 8 banks with a busy time of 6 cycles. A vector loop walks one column (stride 128). Which changes remove the bank conflicts? Select all that apply.
On a machine without chaining, when can ADDVV.D V4, V2, V3 start, if V2 comes from MULVS.D V2, V1, F0?
Key take-aways
- A convoy is a set of vector instructions that execute together: at most one per functional unit, and a true dependence inside a convoy only with chaining. A chime is one convoy's time, VL cycles on one lane, so T ≈ m × VL with start-up ignored.
- Chaining forwards each element of a result to the next unit as soon as it is produced, so a dependent instruction joins its producer's convoy: DAXPY drops from 4 convoys (256 cycles) to 3 (192).
- In the papers' quiz the single load/store unit sets the count — memory instructions are a floor for the convoys: 4 × 16 = 64 (July 2024, June 2026), 4 × 8 = 32 (June 2025; 6 × 8 = 48 if packed strictly in listing order), 5 × 8 = 40 (February 2025). The 2025 and 2026 papers offer the count without chaining as a wrong option.
- L lanes put element i in lane i mod L and divide every chime, T ≈ m × ⌈VL/L⌉, with the same instructions and the same binary.
- MVL is the hardware length of a register, VLR (0 ≤ VLR ≤ MVL) the software knob; strip mining cuts n elements into ⌈n/MVL⌉ strips with a short strip of n mod MVL: 260 = 4 × 64 + 4 = 8 × 32 + 4.
- A vector mask register keeps a loop with an if vectorizable, but masked elements still take their cycle.
- A strided access visits #banks / gcd(stride, #banks) banks and stalls when that is less than the bank busy time: a 128-word column on 8 banks hits one bank, and padding the rows to 129 words spreads it over all eight.
What to watch and read
-
Digital Design and Comp. Arch. – Lecture 19: SIMD Architectures (Vector and Array Processors)
Onur Mutlu, ETH Zürich
Array processors against vector processors, vector length and stride registers, lanes, and chaining drawn as pipeline timing diagrams: the pictures to have in mind before counting convoys.
-
L22: Vector Computers
MIT 6.823 (Emer; notes by Asanović and Arvind)
Chaining, lanes, the strip-mined loop, masks, gather/scatter and memory banks in the order of this lesson, by authors of the vector chapter of Hennessy & Patterson.
-
The CRAY-1 Computer System
Richard M. Russell, Communications of the ACM, 1978
The machine VMIPS imitates, described by its makers: eight 64-element vector registers, vector length and mask registers, chaining and 16 memory banks.
-
RISC-V Vector extension in a nutshell (part 1)
FPRox
How a modern ISA does VLR and strip mining: vsetvli returns the vector length of each strip; a short, gentle read.
-
"V" Standard Extension for Vector Operations, version 1.0
RISC-V International
The real-world reference for this lesson: unit-stride, strided and indexed (gather/scatter) loads, the mask in v0, and a strip-mined loop written around vsetvli.