This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Missed possible branch elimination


On Thu, Oct 26, 2017 at 8:23 PM, Stefan Ring <stefanrin@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? ;)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]