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.

Reply via email to