This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
Re: Shifting: what's going on?
Facundo Ciccioli writes:
> Hi. What follows applies to gcc (GCC) 3.4.2 (mingw-special), platform
> x86-32bits.
>
> This code:
>
> int main() {
> unsigned long long a= 1;
> unsigned s= 63;
>
> a= (a << s);
>
> return 0;
> }
> generates this assembler (removing preamble and prologue stuff):
>
> movl $1, -8(%ebp)
> movl $0, -4(%ebp)
> movl $63, -12(%ebp)
> movl -12(%ebp), %ecx
> movl -8(%ebp), %eax
> movl -4(%ebp), %edx
> shldl %cl,%eax, %edx
> sall %cl, %eax
> testb $32, %cl
> je L2
> movl %eax, %edx
> movl $0, %eax
> L2:
> movl %eax, -8(%ebp)
> movl %edx, -4(%ebp)
>
> This is fine, and works as I expect.
> However, this code:
>
> int main() {
> unsigned long long a;
> unsigned s= 63;
>
> a= (1 << s);
>
> return 0;
> }
> generates this assembler:
>
> movl $63, -12(%ebp)
> movl -12(%ebp), %ecx
> movl $1, %eax
> sall %cl, %eax
> cltd
> movl %eax, -8(%ebp)
> movl %edx, -4(%ebp)
> which is... wrong. Not only the results aren't what they should, but
> looking a little harder, the assembler generated doesn't seem to make
> sense. What's with the CLTD instruction there? If I change s (the
> shifted amount) to be 63 (31 is equivalent, because only 5 bits of %cl
> are used) then the result are a bunch of 1's because the sign of %eax
> goes all over %edx. And that's only one problem. If s is between 62
> and 32, the 1 appears in %eax instead of being in %edx, where it
> should.
>
> This is obviusly not urgent, since the first code is perfectly
> acceptable and applicable to what I am doing, but I just got curious.
This is an arithmetic overflow, and is explicitly undefined. One
result is as good as any other. What do you expect the code to do?
Andrew.
--
Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SL4 1TE, UK
Registered in England and Wales No. 3798903