XOR'ing a register with itself is the idiom for zeroing it out. Why not sub?

An exploration of why the `xor eax, eax` idiom became the standard for zeroing registers in x86 assembly, comparing it with `sub eax, eax` and examining hardware optimizations and historical preferences.
Matt Godbolt, probably best known for being the proprietor of Compiler Explorer, wrote a brief article on why x86 compilers love the xor eax, eax instruction. The answer is that it is the most compact way to set a register to zero on x86. In particular, it is several bytes shorter than the more obvious mov eax, 0 since it avoids having to encode the four-byte constant. The x86 architecture does not have a dedicated zero register, so if you need to zero out a register, you’ll have to do it ab initio. But Matt doesn’t explain why everyone chooses xor as opposed to some other mathematical operation that is guaranteed to result in a zero? In particular, what’s wrong with sub eax, eax? It encodes to the same number of bytes, executes in the same number of cycles. And its behavior with respect to flags is even better. Observe that xor eax, eax leaves the AF flag undefined, whereas sub eax, eax clears it. I don’t know why xor won the battle, but I suspect it was just a case of swarming. In my hypothetical history, xor and sub started out with roughly similar popularity, but xor took a slightly lead due to some fluke, perhaps because it felt more “clever”. When early compilers used xor to zero out a register, this started the snowball. The predominance of these idioms led Intel to add special xor/sub-detection in the instruction decoding front-end and rename the destination to an internal zero register, bypassing execution entirely. This also breaks dependency chains. Even though Intel added support for both, other CPU manufacturers like VIA Nano 2000 may have special-cased xor but not sub. AMD manuals for a long time only recommended xor. The xor trick doesn’t work for Itanium because mathematical operations don’t reset the NaT bit, but Itanium has a dedicated zero register anyway.
Source: Hacker News















