Earlier quoted context omitted.
Quite a few architectures have a dedicated 0 register.
Indeed!! MIPS - $zero RISC-V - x0 SPARC - %g0 ARM64 - XZR
XOR'ing a register with itself is the idiom for zeroing it out. Why not sub?
141–150 of 231 posts
Re: XOR'ing a register with itself is the idiom for zeroing it out. Why not sub?
#142The hw implementation of xor is simpler than sub, so it should consume slightly less energy. Wondering how much energy was saved in the whole world by using xor instead of sub.
Re: XOR'ing a register with itself is the idiom for zeroing it out. Why not sub?
#143Earlier quoted context omitted.
The non-obvious bit is why there isn't an even faster and shorter "mov ,0" instructions - the processors started short-circuiting xor , much later.
In x86, a basic immediate instruction with a 1 Byte immediate value is encoded like this: (1 Byte opcode), (1 Byte), (1 Byte) While xor eax, eax only uses 2 bytes. Since there are only 8 registers, meaning they can be encoded with 3 bits, you can pack two values into the field (ModR/M). Making mov eax, 0 only take two bytes would require significant changes of the ISA to allow immediate values in the ModR/M byte (or…
It could have been added to x86, even as a group of single-byte opcodes with the register encoded in three bits (as with PUSH, POP, and INC/DEC outside of long mode). But the XOR idiom was already established on the 8080 by that point.
Re: XOR'ing a register with itself is the idiom for zeroing it out. Why not sub?
#144latency (L) and throughput (T) measurements from the InstLatx64 project (https://github.com/InstLatx64/InstLatx64) :
| GenuineIntel | ArrowLake_08_LC | SUB r64, r64 | L: 0.26ns= 1.00c | T: 0.03ns= 0.135c |
| GenuineIntel | ArrowLake_08_LC | XOR r64, r64 | L: 0.03ns= 0.13c | T: 0.03ns= 0.133c |
| GenuineIntel | GoldmontPlus | SUB r64, r64 | L: 0.67ns= 1.0 c | T: 0.22ns= 0.33 c |
| GenuineIntel | GoldmontPlus | XOR r64, r64 | L: 0.22ns= 0.3 c | T: 0.22ns= 0.33 c |
| GenuineIntel | Denverton | SUB r64, r64 | L: 0.50ns= 1.0 c | T: 0.17ns= 0.33 c |
| GenuineIntel | Denverton | XOR r64, r64 | L: 0.17ns= 0.3 c | T: 0.17ns= 0.33 c |
I couldn't find any AMD chips where the same is true.Re: XOR'ing a register with itself is the idiom for zeroing it out. Why not sub?
#145Earlier quoted context omitted.
It's still the same number of clock cycles, though, isn't it? You're using some extra circuitry during the SUB, but during the XOR, that circuitry is just sitting idle anyway, so it's still six of one/half a dozen of the other.
XOR can do everything in 1 cycle (which is hopefully far, far less than the clock). SUB-if done the simple way-has to take n cycles where n is the number of bits subtracted.
There is sequential implementation of ripple carry adder that uses clock and register, this will add 1-bit per cycle, but no body uses this for obvious reason, it's just a toy example for education. A normal ripple carry adder will have some delay in propagation time before the output is valid, but that is much less a clock cycle. You can also design a customized adder circuit for 4-bit 8-bit 16-bit etc separately that would greatly minimizes the propagation delay to only 2 or 3 levels of gates, instead of n gates like in the ripple carry adder.
Re: XOR'ing a register with itself is the idiom for zeroing it out. Why not sub?
#146Relatedly, there's a steganographic opportunity to hide info in machine code by using "XOR rax,rax" for a "zero" and "SUB rax,rax" for a "one" in your executable. Shouldn't be too hard to add a compiler feature to allow you to specify the string you want encoded into its output.
You can do better. X86 has both "op [mem], reg" and "op reg, [mem]" variants of most instructions, where "[mem]" can be a register too. So you have two ways to encode "xor eax, eax", differing by which of the operands is in the "possible memory operand" slot, the source or the destination.
Re: XOR'ing a register with itself is the idiom for zeroing it out. Why not sub?
#147Earlier quoted context omitted.
In a clockless cpu design you'd indeed expect xor to be faster. But in a regular CPU with a clock you either waste a bit of xor performance by making xor and sub both take the same number of ticks, or you speed up the clock enough that the speed difference between xor and sub justifies sub being at least a full tick slower The former just seems way more practical
Even if they take the same number of ticks, shouldn't xor fundamentally needing less work also mean it can be performed while drawing less power/heating less, which is just as much an improvement in the long run?
Re: XOR'ing a register with itself is the idiom for zeroing it out. Why not sub?
#148Earlier quoted context omitted.
On modern ones, x86 has quite a history and the idiom might carry on from an even older machine. Edit: Looked at comments, seems like x86 and the major 8bit cpu's had the same speed, pondering in this might be a remnant from the 4-bit ALU times.
Nope. In any ALU the speed is determined by the slowest operation, so XOR is never faster. It does not matter which is the width of the ALU, all that matters is that an ALU does many kinds of operations, including XOR and subtraction, where the operation done by an ALU is selected by some control bits. I have explained in another comment that the only CPUs where XOR can be faster than subtraction are the so-called su…
On a 386, a reg/reg ADD is 2 cycles. An r32 IMUL is "9-38" cycles.
If what you stated were true, you'd be locking XOR's speed to that of DIV. (Or you do not consider MUL/DIV "arithmetic", or something.)
https://www2.math.uni-wuppertal.de/~fpf/Uebungen/GdR-SS02/op...
> I have explained in another comment that the only CPUs where XOR can be faster than subtraction are the so-called superpipelined CPUs. Superpipelined CPUs have been made only after 1990 and there were very few such CPUs.
(And I'm choosing 386 to avoid it being "a superpipelined CPU".)
Re: XOR'ing a register with itself is the idiom for zeroing it out. Why not sub?
#149XOR is a simple logic-gate operation. SUB would have to be an ALU operation. A one-bit adder (which is subtraction in reverse) makes signals pass through two gates. See https://en.wikipedia.org/wiki/Adder_(electronics) You need the 2 gates for adding/subtracting because you care about carry. So if you're adding/subtracting 8 bits, 16 bits, or more, you're connecting multiples of these together, and that carry has to…
That's all true, but on any modern x86 processor both the single pair of gates for the xor and the 10 or so for a carry-bypass 64 bit wide subtraction both happen with a single clock cycle of latency so from a programmer's perspective they're the same in that sense. There's still an energy difference but its tiny compared to what even the register file and bypass network for the operation use, let along the OoO struc…
Re: XOR'ing a register with itself is the idiom for zeroing it out. Why not sub?
#150Earlier quoted context omitted.
XOR can do everything in 1 cycle (which is hopefully far, far less than the clock). SUB-if done the simple way-has to take n cycles where n is the number of bits subtracted.
That's just not true. You think subtracting/adding 64-bit numbers actually take 64 cycles? There is sequential implementation of ripple carry adder that uses clock and register, this will add 1-bit per cycle, but no body uses this for obvious reason, it's just a toy example for education. A normal ripple carry adder will have some delay in propagation time before the output is valid, but that is much less a clock cyc…