satz@CISCO.COM (01/04/89)
We have a single piece of code which has given compilers from many
different types of systems fits. Apparently the case table generation code
was enhanced since gcc 1.30, the last release we used. gcc 1.32 on a Sun
3/280 (68020) running SunOS 3.5 tries to structure the case table into a
tree of conditionals so the cost of any item in the table was o(log n).
gcc 1.30 just tested for each value which for the end of list was o(n).
Unfortunately it seems that the unsignedness of the value was overlooked or
broken.
long test (unsigned short arg)
{
switch ((unsigned int)arg) { /* removing this cast makes it work too */
case 0x0800: return(1);
case 0x0806: return(2);
case 0x0200: return(3);
case 0x0201: return(4);
case 0x8035: return(5);
case 0x0804: return(6);
case 0x6003: return(7);
case 0x9000: return(8);
case 0x0600: return(9);
case 0x8038: return(10);
default: return(-1);
case 0: return(-2);
}
}
main()
{
printf("result = %d\n",test(0x9000));
}
Will return -1 when it should return 8. The following assembler is
generated with -O:
#NO_APP
gcc_compiled.:
.text
.even
.globl _test
_test:
link a6,#0
movew a6@(10),d0
cmpw #2052,d0
jeq L8
jgt L16
cmpw #513,d0
jeq L6
jgt L17
tstw d0
jeq L14
cmpw #512,d0
jeq L5
jra L13
L17:
cmpw #1536,d0
jeq L11
cmpw #2048,d0
jeq L3
jra L13
L16:
cmpw #32821,d0
jeq L7
jgt L18
cmpw #2054,d0
jeq L4
cmpw #24579,d0
jeq L9
jra L13
L18:
cmpw #32824,d0
jeq L12
cmpw #36864,d0
jeq L10
jra L13
L3:
moveq #1,d0
jra L1
L4:
moveq #2,d0
jra L1
L5:
moveq #3,d0
jra L1
L6:
moveq #4,d0
jra L1
L7:
moveq #5,d0
jra L1
L8:
moveq #6,d0
jra L1
L9:
moveq #7,d0
jra L1
L10:
moveq #8,d0
jra L1
L11:
moveq #9,d0
jra L1
L12:
moveq #10,d0
jra L1
L13:
moveq #-1,d0
jra L1
L14:
moveq #-2,d0
L1:
unlk a6
rts
LC0:
.ascii "result = %d\12\0"
.even
.globl _main
_main:
link a6,#0
movel #36864,sp@-
jbsr _test
movel d0,sp@-
pea LC0
jbsr _printf
unlk a6
rts
Note that 0x9000 has the sign bit set for unsigned short values and that
the jump/test instructions aren't ignoring the sign bit. Modifying the
variable used in the switch statement to be unsigned long is the
work-around we used.
PS. gcc-1.30 generated the following code with -O:
#NO_APP
.text
.even
.globl _test
_test:
link a6,#0
movew a6@(10),d0
jeq L14
cmpw #32824,d0
jeq L12
cmpw #1536,d0
jeq L11
cmpw #36864,d0
jeq L10
cmpw #24579,d0
jeq L9
cmpw #2052,d0
jeq L8
cmpw #32821,d0
jeq L7
cmpw #513,d0
jeq L6
cmpw #512,d0
jeq L5
cmpw #2054,d0
jeq L4
cmpw #2048,d0
jne L13
moveq #1,d0
jra L1
L4:
moveq #2,d0
jra L1
L5:
moveq #3,d0
jra L1
L6:
moveq #4,d0
jra L1
L7:
moveq #5,d0
jra L1
L8:
moveq #6,d0
jra L1
L9:
moveq #7,d0
jra L1
L10:
moveq #8,d0
jra L1
L11:
moveq #9,d0
jra L1
L12:
moveq #10,d0
jra L1
L13:
moveq #-1,d0
jra L1
L14:
moveq #-2,d0
L1:
unlk a6
rts
LC0:
.ascii "result = %d\12\0"
.even
.globl _main
_main:
link a6,#0
movel #36864,sp@-
jbsr _test
movel d0,sp@-
pea LC0
jbsr _printf
unlk a6
rts