On Thu, Oct 26, 2017 at 8:23 PM, Stefan Ring <stefan...@gmail.com> wrote: > While poring over the Transport Tycoon Deluxe disassembly, commonly > known to have been hand-written in assembler, I stumbled across this > tidbit, which I think is kinda neat: > > 004057F7 83 7D B8 01 cmp dword ptr [ebp-48h],1 > 004057FB 1B C0 sbb eax,eax > 004057FD F7 D8 neg eax > 004057FF 85 05 20 A9 41 00 test dword ptr ds:[41A920h],eax > 00405805 0F 84 91 00 00 00 je 0040589C > > which basically says: > > if (((DWORD*) $ebp)[-0x12] == 0 && (*(DWORD*) 0x41a920 & 1)) { <whatever> } > > ... leaving aside possible side effects of the memory access, so > treating short circuit eval like an arithmetic operation might not be > legal in this specific case. But for the function > > void a(void (*fnc)(void), int *x, int y) { if ((*x == 0) && (y&1)) fnc(); } > > & and && should be absolutely equivalent. In fact, gcc realizes this > equivalency and produces the exact same code for both variants. It is > just using the two-branch version instead of a one-branch strategy > (x86_64 now): > > 0000000000000000 <a>: > 0: 8b 06 mov (%rsi),%eax > 2: 85 c0 test %eax,%eax > 4: 75 0a jne 10 <a+0x10> > 6: 83 e2 01 and $0x1,%edx > 9: 74 05 je 10 <a+0x10> > b: ff e7 jmpq *%rdi > d: 0f 1f 00 nopl (%rax) > 10: c3 retq > > I would rather see: > > 0000000000000000 <a>: > 0: 31 c0 xor %eax,%eax > 2: 8b 0e mov (%rsi),%ecx > 4: 85 c9 test %ecx,%ecx > 6: 0f 94 c0 sete %al > 9: 85 c2 test %eax,%edx > b: 74 03 je 10 <a+0x10> > d: ff e7 jmpq *%rdi > f: 90 nop > 10: c3 retq > > Either that, or even: > > 0000000000000000 <a>: > 0: 8b 0e mov (%rsi),%ecx > 2: 85 c9 test %ecx,%ecx > 4: 0f 94 c0 sete %al > 7: 84 c2 test %al,%dl > 9: 74 05 je 10 <a+0x10> > b: ff e7 jmpq *%rdi > d: 0f 1f 00 nopl (%rax) > 10: c3 retq > > Although this is touching an entirely different topic now. > > I'm just wondering if it should not rather lean towards eliminating > the branch. I'd > guess that this almost always a worthy goal.
I'm really curious about that. Why is it that two branches instead of one are preferred, even if the compiler seems to realize equivalence, given that it replaces an arithmetic operation (the & operator) with a branch. It would seem that this is a case of if conversion, albeit in the wrong direction for my taste. Is this question not appropriate here? Did nobody know what to make of it? Or my expectations? ;)