This page is the "hands dirty" companion to the parent topic. There we argued why a CPU that only touches memory through load and store wins. Here we prove it by grinding through every kind of situation the model can throw at you: single ops, expression trees, register shortages, and the degenerate edge cases (zero memory ops, everything already in registers, a cache miss on every access).
Before line one, three words we will lean on constantly, in plain English:
We also need two measuring sticks, defined before we ever use them:
And three words about registers running out, defined here so the spill example makes sense:
One more word we will need from Example 6 onward — define it now before we lean on it:
Every load/store problem is one (or a mix) of the cells below. The worked examples that follow are each tagged with the cell they cover, and together they fill the whole grid.
Figure 1 — The nine scenario cells laid out as a grid. Cells A–E (blue row, left) vary the shape of the computation, from a single round-trip up to register spilling. Cells F–I (green row, right) vary the cost model applied to it — timing showdown, cache-miss worst case, a word problem, and the exam trap. The whole page is a walk through this grid.
Figure 2 — The baseline round-trip for x = x + 1. The blue arrow (load) carries x out of the memory box on the left into register R2 on the counter; the ALU adds 1 (yellow); the red arrow (store) carries the result back. Two arrows cross the wall = two memory accesses; the add in the middle touches only registers.
Figure 3 — Expression tree for (a + b) - c. Leaves a, b, c (blue) are loaded from memory; the inner node a+b (yellow) is an intermediate that has nowhere to live but a register; the root - (red) produces r. Every non-leaf node = one value that must occupy a register until its parent consumes it.
Figure 4 — All operands already resident on the counter. No arrow crosses the memory wall (greyed out on the left); the ALU multiplies R1*R2 then adds R3, entirely register-to-register. This is the cheapest shape a load/store machine can run.
Now the ugly case. Imagine a toy CPU with only 3 usable registers R1,R2,R3, and we must compute y = a + b + c + d where all four live in memory.
Figure 5 — Streaming accumulation. Time runs left to right across the four steps. The red bar spanning the whole width is register R3, the running sum — it stays live from the first add to the store and is never evicted. The short blue blocks are transient input registers (R1,R2, then R1 reused for c, then R1 reused for d), each appearing only when needed. The green arrow is the punchline: pressure never exceeds 3, so no spill occurs.
Figure 6 — Where constants live. The variable a (blue) is loaded from the memory box across the wall. The constants 4 and #10 (yellow) ride inside the instruction word itself — shown as small badges attached to the MUL and ADD boxes — so they cost no memory access. Only one arrow crosses the wall inbound, one outbound.
This is the crossover the parent note claimed. Let's compute both wall-clock times end to end.
Figure 7 — Cycles as bar height (= CPI). The single red bar is x86's one fused instruction, height 10, because its hidden read-modify-write costs 10 cycles and cannot overlap itself. The three short blue bars are ARM's LDR, ADD, STR, each 4 cycles tall. The yellow arrow marks the key reading: total coloured area is nearly equal, and area (bars × height ≈ total cycles) × Tclk = time, so both finish in ~4 ns.
x86 (register-memory): 1 instruction, but it fuses read-modify-write → CPI = 10, clock f=2.5 GHz so Tclk=0.4 ns.
ARM (load/store): 3 instructions (LDR, ADD, STR), overlap hides one cache miss (the ~10-cycle stall defined above) → CPI = 4, clock f=3 GHz so Tclk≈0.33 ns.
Figure 8 — The cold-cache limit. Each of the five memory accesses (red blocks) pays the full 10-cycle miss latency with no overlap — the blocks stack end to end because a dependency chain forbids hiding them. The three ALU ops (blue) add just 1 cycle each. The tall red total dwarfs the blue: this is where CPI blows up.
Figure 9 — Sensor averaging pipeline. Two blue arrows load t1 and t2 from their memory addresses into R1, R2; the ALU adds them (yellow) then shifts right by one bit — a right-shift halves a binary number because every bit slides to a place worth half as much. The red arrow stores the average back to 0x28.
Figure 10 — The trap visualised. Left: Machine P, only 2 instructions but each very costly (tall red bars, CPI 8). Right: Machine Q, 4 slim instructions (short blue bars, CPI 2) on a clock twice as fast. The green total-time labels reveal the verdict: Q's stack is 4× shorter in real time despite having more bars.
Recall Why does an ALU op never name a memory address?
Because in a load/store architecture only load/store instructions touch memory — keeping ALU ops fast, fixed-latency, and easy to pipeline. ::: The ALU can only read/write registers.
Recall The one fair scoreboard for speed
Execution time. ::: T=I×CPI×Tclk — never instruction count alone.
Recall What makes a value "live", and what is a spill?
Live = already computed and still needed later; a spill = storing a live value to memory (and reloading it) when register pressure exceeds the register count. ::: Spill costs one extra store + one extra load.
Recall Cache hit vs cache miss latency (as used on this page)
Hit ≈ 1 cycle, miss ≈ 10 cycles. ::: The ~10× gap is what makes memory timing variable.
Recall Cold-cache worst-case CPI from Example 7
With 5 misses × 10 cycles + 3 ALU × 1 over 8 instructions. ::: 53/8=6.625.
Recall Example 9 verdict
Which machine wins and by how much? ::: Load/store machine Q, TQ=2 ns vs TP=8 ns — 4× faster.