Re: optimizer discards sign information

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

 



On Wed, 2024-04-10 at 12:16 +0300, Alexander Monakov wrote:
> 
> 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.

Also note that -fsanitize=undefined detects the issue properly:

$ cat t.c
typedef unsigned long long int u64;
typedef unsigned int u32;
typedef unsigned short u16;

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

int main()
{
	__builtin_printf("%llx\n", foo(65535, 65535));
}
$ cc t.c -O2 -fsanitize=undefined
$ ./a.out
t.c:7:15: runtime error: signed integer overflow: 65535 * 65535 cannot be represented in type 'int'
fffe0001

-- 
Xi Ruoyao <xry111@xxxxxxxxxxx>
School of Aerospace Science and Technology, Xidian University




[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