Live data from Hacker News

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

devblogs.microsoft.com

31–40 of 231 posts

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

#31
post #4

The obvious answer is that XOR is faster. To do a subtract, you have to propagate the carry bit from the least-significant bit to the most-significant bit. In XOR you don't have to do that because the output of every bit is independent of the other adjacent bits. Probably, there are ALU pipeline designs where you don't pay an explicit penalty. But not all, and so XOR is faster. Surely, someone as awesome as Raymond C…

That comment is not very useful without pointing to realworld CPUs where SUB is more expensive than XOR ;) E.g. on Z80 and 6502 both have the same cycle count.

Cortex A8 vsub reads the second source register a cycle earlier than veor, so that can add one cycle latency

Not scalar, but still sub vs xor. Though you’d use vmov immediate for zeroing anyway.

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

#32
post #27
post #15

"Bonus bonus chatter: The xor trick doesn’t work for Itanium because mathematical operations don’t reset the NaT bit. Fortunately, Itanium also has a dedicated zero register, so you don’t need this trick. You can just move zero into your desired destination." Will remember for the next time I write asm for Itanium!

Quite a few architectures have a dedicated 0 register.

indeed. riscv for instance. also, afaik, xor’ing is faster. i would assume that someone like mr. raymond would know…

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

#33

Back in the stone ages XOR ing was just 1 byte of opcode. Habbits stick. In effect XORing is no longer faster since a long time.

The XOR trick is implemented as a (malloc from register file) on modern processors, implemented in the decoder and it won't even issue a uOp to the execution pipelines.

Its basically free today. Of course, mov RAX, 0 is also free and does the same thing. But CPUs have limited decoder lengths per clock tick, so the more instructions you fit in a given size, the more parallel a modern CPU can potentially execute.

So.... definitely still use XOR trick today. But really, let the compiler handle it. Its pretty good at keeping track of these things in practice.

-----------

I'm not sure if "sub" is hard-coded to be recognized in the decoder as a zero'd out allocation from the register file. There's only certain instructions that have been guaranteed to do this by Intel/AMD.

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

#34
post #10

Once an instruction has an edge, even if only extremely slight, that’s enough to tip the scales and rally everyone to that side. And this, interestingly, is why life on earth uses left-handed amino acids and right-handed sugars .. and why left handed sugar is perfect for diet sodas.

You still need to explain why this case creates a positive feedback loop rather than a negative one. I mean left/right fuel intakes in cars and male/female ratios somehow tend to balance at 50/50.

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

#35

It might be because XOR is rarely (in terms of static count, dynamically it surely appears a lot in some hot loops) used for anything else, so it is easier to spot and identify as "special" if you are writing manual assembly.

XOR appears a lot in any code touching encryption.

PS. What is static vs dynamic count?

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

#36
post #4

The obvious answer is that XOR is faster. To do a subtract, you have to propagate the carry bit from the least-significant bit to the most-significant bit. In XOR you don't have to do that because the output of every bit is independent of the other adjacent bits. Probably, there are ALU pipeline designs where you don't pay an explicit penalty. But not all, and so XOR is faster. Surely, someone as awesome as Raymond C…

I would be surprised if modern CPUs didn't decode "xor eax, eax" into a set of micro-ops that simply moves from an externally invisible dedicated 0 register. These days the x86 ISA is more of an API contract than an actual representation of what the hardware internals do.

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

#37
post #17

Looking at some random 1989 Zenith 386SX bios written in assembly so purely programmer preferences: 8 'sub al, al', 14 'sub ah, ah', 3 'sub ax, ax' 26 'xor al, al', 43 'xor ah, ah', 3 'xor ax, ax' edit: checked a 2010 bios and not a single 'sub x, x'

Could be used to express 1 bit of information in some non-obvious convention.

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

#38
post #27
post #15

"Bonus bonus chatter: The xor trick doesn’t work for Itanium because mathematical operations don’t reset the NaT bit. Fortunately, Itanium also has a dedicated zero register, so you don’t need this trick. You can just move zero into your desired destination." Will remember for the next time I write asm for Itanium!

Quite a few architectures have a dedicated 0 register.

Indeed!!

MIPS - $zero

RISC-V - x0

SPARC - %g0

ARM64 - XZR

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

#39

Earlier quoted context omitted.

And helps with SMT Edit: this is apparently not the case, see @tliltocatl's comment down the thread

What's SMT in this context?

Simultaneous Multi-Threading (hyper-threading as Intel calls it). I'm not a cpu guy, but I think the ALU used for subtraction would be a more valuable resource to leave available to the other thread than whatever implements a xor. Hence you prefer to use the xor for zeroing and conserve the ALU for other threads to use.

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

#40
post #20
post #9

Earlier quoted context omitted.

His point is that in x86 there is no performance difference but everyone except his colleague/friend uses xor, while sub actually leaves cleaner flags behind. So he suspects its some kind of social convention selected at random and then propagated via spurious arguments in support (or that it “looks cooler” as a bit of a term of art). It could also be as a result of most people working in assembly being aware of the…

I think an even more likely explanation would be that x86 assembly programmers often were, or learned from other-architecture assembly programmers. Maybe there's a place where it makes more sense and it can be so attributed. 6502 and 68k being first places I would look at.

For 68k depending on the size you're interested in then it mostly doesn't matter.

.b and .w -> clr eor sub are all identical

for .l moveq #0 is the winner

Post reply on HN