← Chapter 8: Branching Chapter 10: Why occupancy matters →
date 23 / jun / 26
mtwtfss
INSIDE THE SILICON — Chapter 9 index home

What is SIMT? (and how it differs from SIMD)

*worked out from first principles*

Both a CPU and a GPU need to do one thing well: run lots of math at once. And underneath, they both reach for the same basic idea before splitting into two completely different designs.

Understanding where they agree first, and then exactly where they fork, is one of those things that quietly separates people who know hardware from people who just memorized acronyms.

The Seed: Decode once, compute many

Start at the bottom, with the one problem all of this exists to solve. Running any instruction takes two kinds of hardware. A control unit, the manager, which fetches the instruction, decodes it, and tells the workers what to do. And an ALU, the worker, which does the actual math. The catch is that the manager is expensive. It eats up chip area and power. The worker is comparatively cheap.

So say you need to add 32 numbers. You have two extremes. One: give every number its own manager and its own worker, 32 of each. That's absurdly wasteful, because all 32 managers are decoding the exact same instruction, paying for the same expensive thing 32 times over. Or two: keep a single manager that decodes the instruction once, and have it send that one command to 32 workers at the same time.

↳ The second option is obviously smarter, and it's the seed of both designs. Decode once, compute many. Share the expensive manager, multiply the cheap workers. SIMD and SIMT both grow out of this exact instinct. They only differ in how they wire the workers up.

Here's where they fork.

SIMD (Single Instruction, Multiple Data)

SIMD is the CPU's approach. Its idea is: make the register really wide. Picture one long 512-bit register where you pack in 16 separate numbers side by side. A single ALU then operates on that whole wide register in one go, hitting all 16 numbers at once.

The key thing to notice is that there are no threads here at all. One CPU thread is driving that entire wide register. The data is just packed lanes inside one big slot.

SIMT (Single Instruction, Multiple Threads)

SIMT is the GPU's approach, and it makes the opposite choice. It says, don't widen the register; instead, give every worker its own small private register and call each worker a thread.

When a warp of 32 threads runs, the hardware fetches one instruction and broadcasts it to 32 separate scalar workers, each holding its own data in its own register, each with its own ID. They look independent from the programmer's seat, but physically they're all firing the same instruction together.

SIMD (CPU Approach) 1 Thread, 1 Wide Register Thread 1 Lane 1 Lane 2 Lane 3 Lane 4 Manually packed array of data. Programmer handles the masking. SIMT (GPU Approach) Many Threads, Private Registers Instruction Fetch T1 Reg T2 Reg T3 Reg T32 Reg Separate hardware threads. Hardware automatically handles masking.

So SIMD packs many numbers into one wide lane driven by one thread. SIMT gives many threads their own narrow lanes driven by one shared instruction. Same root instinct, mirror-image execution.

The Branching Test

Now the test that exposes the real difference: what happens when the code branches. Say you write: if the value is over 10, double it, otherwise add 5. And half your data goes one way, half the other. Both designs have to deal with this, and how they do it is the whole point.

SIMD handles it with manual masking. The hardware checks all 16 packed values at once and builds a bitmask—a row of 1s and 0s marking which lane passed the test. Then it runs the doubling across everything but only keeps the results in lanes marked 1. Then it runs the add-5 across everything but only keeps the results in lanes marked 0. It does both operations and uses the mask to throw away the half it doesn't want, lane by lane. It works, but it's rigid, and the programmer often has to spell out this masking by hand. For a complex loop, writing that masking yourself is genuinely painful.

SIMT handles the same branch with hardware serialization. The warp activates the 16 threads that took the if path, disables the other 16, and runs the first path. Then it flips, disabling the first 16 and enabling the second 16 to run the else path. Half the workers sit idle during each phase, so the warp runs at half efficiency. This is the divergence penalty.

The Real Upgrade: Flexibility

So here's the sharp interview question that follows. If both of them end up running the two branches one after the other anyway, why is SIMT called a better, newer model? What's the actual win?

↳ The answer isn't speed, it's who does the hard work.

In SIMD, the programmer has to manually pack the vectors, build the masks, and shuffle the lanes themselves. The model is rigid and the code gets ugly fast.

In SIMT, the hardware gives you the illusion that every thread is independent. You write plain, normal-looking code with an ordinary if/else, and the hardware quietly handles the masking and the serialization behind your back. SIMT takes the painful bookkeeping off the programmer and buries it in silicon. That's the real upgrade: flexibility, not raw throughput.

A few other differences fall out of this same split:

  • SIMD uses one extra-wide vector worker with divided lanes, while SIMT uses an array of separate scalar workers.
  • SIMD has no real threads, so the data shares one unified register file, while in SIMT every thread owns its own private registers and a unique id.
  • SIMD wants its data packed tightly and contiguously in memory to load a vector efficiently, while SIMT lets each thread reach for its own address and leans on the hardware to gather those scattered accesses together.
  • SIMD hides memory delay through the CPU's cache, while SIMT hides it by juggling a massive number of threads, switching to ready work whenever some threads are stalled waiting on data.

↳ The General Takeaway

Both come from the same frugal instinct: decode an instruction once and spread it across many cheap workers to avoid paying for the expensive manager again and again.

SIMD spreads it across packed lanes in one wide register and hands the programmer the burden of managing them. SIMT spreads it across many threads with private registers and hides that burden inside the hardware.

The CPU chose width and control.
The GPU chose threads and the illusion of independence.