gcc bug/quirk with left shifts on i386 family.

Peter Wemm peter@netplex.com.au
Thu Jan 4 11:14:00 GMT 2001


I'm not sure if this is a real bug or one of those gray 'implementation
defined' areas of the language, but it looks rather strange:

115$ cat shift.c
#include <stdio.h>
main()
{
        int thirtytwo = 32;

        printf("1U << 32 = %d\n", 1U << 32);
        printf("thirtytwo = %d\n", thirtytwo);
        printf("1U << thirtytwo = %d\n", 1U << thirtytwo);
}

116$ cc -o shift shift.c
shift.c: In function `main':
shift.c:6: warning: left shift count >= width of type
(yes, there is a warning as expected.)

117$ ./shift
1U << 32 = 0
thirtytwo = 32
1U << thirtytwo = 1

Note that the value that gcc computes itself is different to what the generated
code computes.  It gets stranger too:

119$ cc -O -S -fomit-frame-pointer shift.c
shift.c: In function `main':
shift.c:6: warning: left shift count >= width of type
120$ cat shift.s
...
        pushl $0	#  1 << 32 precomputed value
        pushl $.LC0
        call printf
...
        pushl $1	#  1 << thirtytwo precomputed value!
        pushl $.LC2
        call printf
...

ie: gcc "optimizes" the two expressions to two different constants.  This
is the quirk.   On the i386 family, 1 << 32 != 1 << variable (where
variable = 32), either when computed as a machine instruction or optimized
to a constant.

Of course, the reason the value is "strange" is that Intel implement
the sall %cl,%eax instruction by discarding all but the bottom 5 bits of
the count.  ie: 1 << 32 == 1 << 0.  This explains the strange value.

I am not quite sure what (if anything) should be done about this.  On one hand
it might be nice to have the code generator have a way to deal with this a
little more sensibly.. but on the other hand there would be a runtime cost
to this.  I am not sure that the cost is worth it.

The really strange thing is that 1 << constant is evaluated differently
to 1 << variable where variable == constant.  That is a bug, I feel.

Versions affected:
121$ cc -v
Using builtin specs.
gcc version 2.95.2 19991024 (release)

daintree.yahoo.com$ egcc -v
Reading specs from /usr/local/lib/gcc-lib/i386-unknown-freebsd5.0/egcs-2.91.66/specs
gcc version egcs-2.91.66 19990314 (egcs-1.1.2 release)

peter@filo.yahoo.com[11:08am]~-102> cc -v
gcc version 2.6.3

img7.yahoo.com 11:09:01 ~ $ cc -v
gcc version 2.7.2.1

These are all FreeBSD/i386 systems of varying ages, but that shouldn't
matter. They all behave the same, so I believe it is a generic i386
compiler problem.  FreeBSD uses a customised version of gcc but that should
not be an issue since at least one of the above compilers shown (egcs 1.1.2)
is an unmodified GNU release and it behaves the same.

Cheers,
-Peter
--
Peter Wemm - peter@FreeBSD.org; peter@yahoo-inc.com; peter@netplex.com.au
"All of this is for nothing if we don't go to the stars" - JMS/B5



More information about the Gcc-bugs mailing list