public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* GCC plays "Shell Game", but looses track of the shell covering the nought
@ 2023-05-27 16:23 Stefan Kanthak
       [not found] ` <20230527113728.26edde9fb121c8c310413fbb@killthe.net>
  0 siblings, 1 reply; 2+ messages in thread
From: Stefan Kanthak @ 2023-05-27 16:23 UTC (permalink / raw)
  To: gcc

--- demo.c ---
int ispowerof2(unsigned long long argument) {
    return (argument != 0) && ((argument & argument - 1) == 0);
}
--- EOF ---

GCC 12.2    gcc -m32 -O3

https://gcc.godbolt.org/z/YWP4zb8jd
ispowerof2(unsigned long long):
        push    edi                        # three registers clobbered
        push    esi                        #  without need, and three
        push    ebx                        #   superfluous memory writes
        mov     edi, DWORD PTR [esp+20]    ->    mov    ecx, [esp+4]
        mov     esi, DWORD PTR [esp+16]    ->    mov    edx, [esp+8]
        mov     eax, edi                   ->    mov    eax, ecx
        or      eax, esi                   ->    or     eax, edx
        je      .L5                        ->    jz     .L0
        mov     eax, esi                   # superfluous
        mov     edx, edi                   # superfluous
        add     eax, -1                    ->    add    ecx, -1
        adc     edx, -1                    ->    adc    edx, -1
        mov     ecx, eax                   # shell game
        mov     eax, esi                   # shell game
        mov     ebx, edx                   # shell game
        mov     edx, edi                   # shell game
        and     eax, ecx                   ->    and    ecx, [esp+4]
        xor     ecx, ecx                   ->    xor    eax, eax
        and     edx, ebx                   ->    and    edx, [esp+8]
        pop     ebx                        # superfluous
        pop     esi                        # superfluous
        or      eax, edx                   ->    or     ecx, edx
        pop     edi                        # superfluous
        sete    cl                         ->    setz   al
        mov     eax, ecx                   # shell game
        ret                        .L0:    ->    ret
.L5:                                       # eax is 0 here!
        xor     ecx, ecx                   # superfluous
        pop     ebx                        # superfluous
        pop     esi                        # superfluous
        mov     eax, ecx                   # superfluous
        pop     edi                        # superfluous
        ret                                # superfluous

OUCH: 19 (in words: NINETEEN) superfluous instructions out of 32, despite -O3,
      3 registers clobbered without need and reason, resulting in
      3 superfluous memory writes

GCC 12.3 generates the same BRAINDEAD code!

GCC 13.3    gcc -m32 -O3

https://gcc.godbolt.org/z/Ge7q4Tv9M
ispowerof2(unsigned long long):
        push    esi                        # two registers clobbered without need,
        push    ebx                        #  two superfluous memory writes
        mov     ecx, DWORD PTR [esp+12]    ->    mov    ecx, [esp+4]
        mov     ebx, DWORD PTR [esp+16]    ->    mov    edx, [esp+8]
        mov     eax, ecx                   ->    mov    eax, ecx
        or      eax, ebx                   ->    or     eax, edx
        je      .L5                        ->    jz    .L0
                                                 xor    eax, eax
        mov     eax, ecx                   # superfluous
        mov     edx, ebx                   # superfluous
        add     eax, -1                    ->    add    ecx, -1
        adc     edx, -1                    ->    adc    edx, -1
        and     eax, ecx                   ->    and    ecx, [esp+4]
        and     edx, ebx                   ->    and    edx, [esp+8]
        pop     ebx                        # superfluous
        or      eax, edx                   ->    or     ecx, edx
        sete    al                         ->    setz   al
        movzx   eax, al                    # superfluous: see xor added above
        mov     esi, eax                   # shell game
        mov     eax, esi                   # shell game
        pop     esi                        # superfluous
        ret                       .L0:     ->    ret
.L5:                                       # eax is 0 here!
        xor     esi, esi                   # superfluous
        pop     ebx                        # superfluous
        mov     eax, esi                   # superfluous
        pop     esi                        # superfluous
        ret                                # superfluous

OUCH: 13 (in words: THIRTEEN) superfluous instructions out of 26, despite -O3,
      2 registers clobbered without need and reason, resulting in
      2 superfluous memory writes

It's e REAL shame how bad GCC's code generator is!

Stefan

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: GCC plays "Shell Game", but looses track of the shell covering the nought
       [not found] ` <20230527113728.26edde9fb121c8c310413fbb@killthe.net>
@ 2023-05-27 17:00   ` Stefan Kanthak
  0 siblings, 0 replies; 2+ messages in thread
From: Stefan Kanthak @ 2023-05-27 17:00 UTC (permalink / raw)
  To: Dave Blanchard; +Cc: gcc

"Dave Blanchard" <dave@killthe.net> wrote:

> Hi Stefan, thanks for sharing this information.
> I was wondering if the code generators in earlier GCC
> versions were any better?

Just open one of the URLs I included, select another GCC version
and see the resulting code.

> Is this a problem in GCC 12+ only?

NO! GCC's code generator REALLY sucks, especially when "double word"
operations are involved.

GCC 6.* generates the following "gem":

.L5: # eax is already 0 here!
        xor     eax, eax
        movzx   eax, al
        pop     ebx
        pop     esi
        ret

GCC 7.* is even worse, it clobbers FOUR registers.

GCC 8.* and 9.* uses/clobbers just one additional register.

GCC 10.* generates the same code as GCC 13.1 with "only" 13 superfluous
instructions (from a total of 26).

GCC 11.* shows the same behaviour with 19 superfluous instructions as 12.*

Also note the difference to yesterdays demo.c: "thanks" to the added
| (argument != 0)
GCC does NOT generate SSE2 instructions any more.

I don't know yet whether this change is a quirk or WTF,

Stefan

> Dave
> 
> 
> On Sat, 27 May 2023 18:23:12 +0200
> "Stefan Kanthak" <stefan.kanthak@nexgo.de> wrote:
> 
>> [...]
>> It's a REAL shame how bad GCC's code generator is!
>> 
>> Stefan

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2023-05-27 17:08 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-27 16:23 GCC plays "Shell Game", but looses track of the shell covering the nought Stefan Kanthak
     [not found] ` <20230527113728.26edde9fb121c8c310413fbb@killthe.net>
2023-05-27 17:00   ` Stefan Kanthak

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).