Re: optimizer discards sign information

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

 



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



[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