The idea: many simple instructions or a few complex ones
An instruction set is the list of instructions a processor understands. A RISC design (reduced instruction set computer: MIPS, ARM, RISC-V) keeps every instruction simple and the same size. A CISC design (complex instruction set computer: x86) lets one instruction do several things, such as read memory, add and write back. The page compiles the same C line for both and runs it.
The values are fixed so every run is the same: a = 0x1000, i = 3, b = 5, and a[3] starts at 40. The arguments arrive in registers, as the calling conventions say: $a0–$a2 on MIPS, rdi, rsi, edx on x86-64 Linux.
Load/store vs memory operands
MIPS is a load/store architecture: only lw and sw touch memory, and arithmetic works on registers only. So a[i] += b needs five steps: shift i left by 2 (×4 bytes), add the base address, load, add b, store (Demo 1: a[i] += b).
x86 allows a memory operand with a scaled-index address: [rdi+rsi*4] means base + index × 4. One instruction, add DWORD PTR [rdi+rsi*4], edx, does the whole line. See how MIPS encodes loads, stores and array access in From C to MIPS Machine Code.
| C line | MIPS32 | x86-64 |
|---|---|---|
a[i] += b; | 5 instructions, 20 bytes | 1 instruction, 3 bytes, 3 µops |
x = y + z; | 1 instruction (addu), 4 bytes | 1 instruction (lea), 3 bytes, 1 µop |
n = 100000; | 2 instructions (lui, ori), 8 bytes | 1 instruction (mov), 5 bytes, 1 µop |
| all three | 8 instructions, 32 bytes, 8 operations | 3 instructions, 11 bytes, 5 µops |
CISC does not always win the count. x = y + z is one instruction on both (Demo 2). MIPS has three register fields, so the result can go to a third register. A plain x86 add overwrites one of its operands, so compilers borrow lea, the address-calculation instruction, as a three-operand add.
Fixed vs variable length decoding
Every MIPS instruction is one 32-bit word. The opcode is always bits 31–26, the register fields always sit at the same bits, and the next instruction always starts 4 bytes later. A decoder can split the word into fields with plain wires.
An x86 instruction is 1 to 15 bytes long. The decoder reads it byte by byte: optional prefixes, then the opcode, which says whether a ModRM byte follows; ModRM says whether a SIB byte and a displacement follow; the opcode also says how many immediate bytes follow. Only at the end does it know where the next instruction starts.
A 32-bit word leaves only 16 bits for a constant. 100000 (0x186A0) does not fit, so MIPS builds it with lui (upper half) and ori (lower half). x86 puts the 4-byte constant inside a 5-byte mov, low byte first (Demo 3: n = 100000).
Micro-ops: x86 is RISC inside
Since the Pentium Pro (1995), x86 cores do not execute complex instructions directly. The decoder cracks each one into micro-ops (µops), simple RISC-like operations. add [rdi+rsi*4], edx becomes load, add, store. The address rdi + rsi·4 is computed by the address unit of the load and the store, so it costs no extra µop: the core does 3 steps of work where MIPS spends 5 instructions.
Real Intel cores split the store again into store-address and store-data, so this instruction is 4 µops in the execution units and 2 in the front end (fused). The µops then flow through the same machinery as on a RISC core: register renaming and out-of-order execution, as in Out-of-Order Execution, and a pipeline, as in The MIPS Pipeline.
The trade-off
| RISC (MIPS, ARM, RISC-V) | CISC (x86) | |
|---|---|---|
| instruction size | fixed, 4 bytes | 1–15 bytes |
| memory access | loads and stores only | most instructions may use memory |
| code size | larger | smaller: more fits in the instruction cache |
| decoder | simple, easy to decode many per cycle | complex length decoding, power hungry |
| registers | 32 general-purpose | 16 general-purpose (x86-64) |
| compiler | more instructions, simple choices | fewer instructions, many ways to say one thing |
In the 1980s, memory was small and slow, so dense CISC code mattered. RISC bet that simple instructions could be pipelined and run at one per cycle. Today both sides borrowed from each other: x86 cores have RISC-like µop engines and a µop cache that skips the hard decoding for hot loops; ARM64 added scaled-index loads like ldr w8, [x0, x1, lsl #2], and RISC-V and ARM offer 2-byte compressed instructions (RVC, Thumb) to shrink code. See where the instruction set sits between the compiler and the hardware in Levels of Abstraction and how code is produced in Compiler Pipeline.
What the page leaves out
Clock cycles and timing (the steps on the page are not cycles), pipelining, superscalar issue and register renaming, the MIPS branch delay slot and the return jr $ra, x86 prefixes (REX, operand size, LOCK), the µop cache and macro-fusion, microcode for very complex instructions like rep movsb, the instruction cache, and RISC-V and ARM64 encodings.