AW: optimizer discards sign information

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> -----Ursprüngliche Nachricht-----
> Von: Gcc-help <gcc-help-bounces+bebbo=bejy.net@xxxxxxxxxxx> Im Auftrag
> von stefan@xxxxxxxxx
> Gesendet: Mittwoch, 10. April 2024 11:25
> An: gcc-help@xxxxxxxxxxx
> Betreff: AW: optimizer discards sign information
> 
> > -----Ursprüngliche Nachricht-----
> > Von: Alexander Monakov <amonakov@xxxxxxxxx>
> > Gesendet: Mittwoch, 10. April 2024 11:17
> > An: stefan@xxxxxxxxx
> > Cc: gcc-help@xxxxxxxxxxx
> > Betreff: Re: optimizer discards sign information
> >
> >
> > On Wed, 10 Apr 2024, stefan@xxxxxxxxx wrote:
> >
> > > Hi all,
> > >
> > > I just stumbled over an issue, which is present in almost all gcc versions.
> > > I worked around using inline assembly… Maybe gcc behaves correct and
> > > I am wrong? Here is the code:
> > >
> > > https://godbolt.org/z/cW8jcdh56
> > >
> > > typedef unsigned long long int u64;
> > > typedef unsigned int u32;
> > > typedef unsigned short u16;
> > >
> > > u64 foo(u16 a, u16 b) {
> > >     u32 x = a * b;
> > >     u64 r = x;
> > >     return r;
> > > }
> > >
> > > And on gcc 13.2 x86.64 you get
> > >
> > > foo:
> > >         movzx   esi, si
> > >         movzx   edi, di
> > >         imul    edi, esi
> > >         movsx   rax, edi
> > >         ret
> > >
> > >
> > > There is a sign extension! The optimizer step discards the
> > > information
> > >
> > > 	 x_6 = (u32) _3;
> > >
> > > and uses _3 directly instead, which is signed.
> > >
> > > Am I wrong or is it gcc?
> >
> > GCC is not wrong. When your code computes x:
> >
> >     u32 x = a * b;
> >
> > 'a' and 'b' are first promoted to int according to C language rules,
> > and the multiplication happens in the signed int type, with UB on overflow.
> > The compiler deduces the range of signed int temporary holding the
> > result of the multiplication is [0, 0x7fffffff], which allows to
> > propagate it to the assignment of 'r' (which in the end produces a
> > sign extension, as you observed, so the propagation did not turn out to be
> useful).
> >
> > u16 * u16 is a famous footgun for sure. I'd suggest 'x = 1u * a * b'
> > as a fix for the code.
> >
> > Alexander
> 
> Thank you for the fix 😊
> I considered
> 
> 	u32 x = a * b;
> 
> as good enough, since from my understanding, x *is* unsigned.
> 
> Adding the multiplication with 1u resolves this.
> 
> regards
> 
> Stefan

But I keep considering this as a bug. And clang behaves correctly!

https://godbolt.org/z/az8WqboET

typedef unsigned long long int u64;
typedef unsigned int u32;
typedef unsigned short u16;

u64 foo(u16 *a, u16 *b) {
    u32 x = *a * *b;
    u64 r = x;
    return r >> 31;
}

gcc yields

foo:
        xor     eax, eax
        ret

clang yields

foo:                                    # @foo
        movzx   ecx, word ptr [rdi]
        movzx   eax, word ptr [rsi]
        imul    eax, ecx
        shr     eax, 31
        ret

regards

Stefan








[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux