1. 13

  2. 2

    This isn’t very specific to go. A lot of RISC ISAs have a zero register defined for reads but something different for writes. Consider a typical RISC instruction. In a 32-bit encoding, 5 bits of this are encoding each operand (with 32 registers). Any non-store instruction has a 5-bit destination so if you allow the zero register as a destination (or as the base address for stores) then you are using 1/32 of your encoding space to encode nops. For comparison, that’s the same amount of the encoding space that AArch64 uses for all load instructions, in all of their complex addressing modes.

    The common alternatives are:

    • Use a 0-encoding in the destination to mean something different. For example, AArch64 uses it to mean the stack pointer when used as the base address for loads and stores, because you almost never actually want to do loads and stores relative to a statically known null pointer.
    • Use a 0-encoding in the destination to identify a hint. It’s fairly common to treat a load with a destination as the zero register as a prefetch hint. This is exactly the opposite of what the author of this article wants, because prefetch instructions typically don’t trap and can be treated as no-ops in simpler implementations.

    It’s also fairly common to retrofit something like this to existing architectures after you run low on encoding space, because no sane compiler generates any no-op that isn’t the canonical no-op. Generally, finding a spare register for the destination of a null check is easy: it’s a register that is live for only the instruction that generates it and so can be the same register as the next instruction uses as its target in the common case. Just plugging in the one-instruction live range to a simple register allocator generally gives good results.