armviz

Why register 31 is two registers

AArch64 has thirty-one general purpose registers. The thirty-second slot, number 31, is not a register of its own. It is a hole in the encoding that the hardware fills in with one of two different meanings depending on what the instruction is doing.

When an instruction names register 31 as a data operand, it means the zero register: reads return zero and writes are discarded. When it names register 31 as a stack pointer, it means the current stack pointer, which is a real register whose value matters.

So X31 does not exist. What exists are XZR and SP, plus their 32-bit forms WZR and WSP. Assemblers let you write xzr, wzr, sp and wsp interchangeably in position, and the assembler picks the encoding that makes the instruction mean what you meant.

The rule is not arbitrary

The reason the two meanings never collide is that no single instruction ever needs both at once. An instruction either moves data, in which case it wants either a real register or the zero register, or it adjusts the stack, in which case it wants the stack pointer and has no use for a zero source.

The result is that the encoding is denser than a design with a dedicated stack pointer register would be, and that SP stays usable in most arithmetic:

add sp, sp, #32      // the stack pointer really is the destination
add x0, sp, #16      // and it can be a source for other instructions
add x0, xzr, x1      // here 31 means zero, not the stack pointer

The first two are stack arithmetic. The third is a plain add, and assemblers write the source as xzr precisely to signal that the zero register is meant.

The same trap in the W aliases

The 32-bit names follow the same pattern. WSP is the low 32 bits of the stack pointer, and WZR is a 32-bit zero register. The distinction matters wherever code narrows the stack pointer, because writing WSP also clears the upper half of the 64-bit stack pointer. That surprise is the subject of writing a W register.

Why the architecture did it this way

A design with a separate stack pointer register would have thirty-two general registers plus SP, which sounds better until you count what an instruction can actually reach. The zero register is not a convenience: it is load-bearing in idiomatic code.

Register moves are everywhere, and mov x0, #0 needs a source that reads as zero. Without the zero register, the standard idiom would be mov x0, xzr with a real register as source, wasting XZR's slot on a fixed value and making every constant load two instructions. The same applies to logical operations that want to leave part of a destination untouched, and to conditional selects that want a zero result for one branch of a condition.