> -----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