lgm@ODDJOB.UCHICAGO.EDU (11/27/88)
SYNOPSIS:
The '-fstrength-reduce' option may handle 'switch' statements
incorrectly. In particular, it can both generate an illegal
assembly statement and transform an address incorrectly.
MACHINE AND OS:
AT&T UNIX PC 3B1 (based on Motorola 68010 microprocessor) running
OS Version 3.5 (compatible with UNIX System V Release 2).
CONFIGURATION FILES:
(usual for the UNIX PC)
"tm-3b1.h"
"xm-3b1.h"
"m68k.md"
"output-m68k.c"
TRANSCRIPT (INPUT FILE, COMMAND LINE, OUTPUT):
_______________________________________
$ cat swit.c
extern int x;
void
f()
{
int i;
for ( i = 0; i < 4; ++i ) {
switch ( i ) {
case 0:
x = 2;
break;
case 1:
x = 3;
break;
case 2:
x = 5;
break;
case 3:
x = 7;
break;
}
}
}
$ gcc -v -S -O swit.c # Without '-fstrength-reduce' option
gcc version 1.31
/usr/local/lib/gcc-cpp -v -undef -D__GNU__ -D__GNUC__ -Dmc68k -Dunix -Dunixpc -D__OPTIMIZE__ swit.c /tmp/cca04439.cpp
GNU CPP version 1.31
/usr/local/lib/gcc-cc1 /tmp/cca04439.cpp -quiet -dumpbase swit.c -O -version -o swit.s
GNU C version 1.31 (68k, SGS/AT&T unixpc syntax) compiled by GNU C version 1.31.
$ cat swit.s
file "swit.c"
text
even
global f
f:
link.w %a6,&0
mov.l %d2,-(%sp)
clr.l %d1
L%12:
mov.l &3,%d2
cmp.l %d1,%d2
bhi.w L%4
mov.l %d1,%d0
asl.l &1,%d0
LI%10: # PC-relative addressing to get
mov.w LD%10(%pc,%d0.w),%d2 # jump offset, uses LD%10
jmp 6(%pc,%d2.w)
swbeg &5
L%10:
short L%10-L%10
short L%6-L%10
short L%7-L%10
short L%8-L%10
short L%9-L%10
set LD%10,L%10-LI%10 # Def. of LD%10 needs LI%10
L%6:
mov.l &2,%d2
bra.w L%13
L%7:
mov.l &3,%d2
bra.w L%13
L%8:
mov.l &5,%d2
bra.w L%13
L%9:
mov.l &7,%d2
L%13:
mov.l %d2,x
L%4:
addq.l &1,%d1
mov.l &3,%d2
cmp.l %d2,%d1
bge.w L%12
mov.l -4(%a6),%d2
unlk %a6
rts
$ gcc -v -S -O -fstrength-reduce swit.c # With '-fstrength-reduce' option
gcc version 1.31
/usr/local/lib/gcc-cpp -v -undef -D__GNU__ -D__GNUC__ -Dmc68k -Dunix -Dunixpc -D__OPTIMIZE__ swit.c /tmp/cca04443.cpp
GNU CPP version 1.31
/usr/local/lib/gcc-cc1 /tmp/cca04443.cpp -quiet -dumpbase swit.c -fstrength-reduce -O -version -o swit.s
GNU C version 1.31 (68k, SGS/AT&T unixpc syntax) compiled by GNU C version 1.31.
$ cat swit.s
file "swit.c"
text
even
global f
f:
link.w %a6,&0
clr.l %d0
mov.l &L%10,%a0 # %a0 starts out as &L%10
L%12:
mov.l &3,%d1
cmp.l %d0,%d1
bhi.w L%4
mov.w (%a0),%d1 # Offset into table at (%a0)
jmp 6(%pc,%d1.w)
swbeg &5
L%10:
short L%10-L%10
short L%6-L%10
short L%7-L%10
short L%8-L%10
short L%9-L%10
set LD%10,L%10-LI%10 # But LI%10 no longer defined!
L%6:
mov.l &2,%d1
bra.w L%13
L%7:
mov.l &3,%d1
bra.w L%13
L%8:
mov.l &5,%d1
bra.w L%13
L%9:
mov.l &7,%d1
L%13:
mov.l %d1,x
L%4:
addq.w &2,%a0
addq.l &1,%d0
mov.l &3,%d1
cmp.l %d1,%d0
bge.w L%12
unlk %a6
rts
$
_______________________________________
EXPLANATION OF TRANSCRIPT:
What '-fstrength-reduce' has done is to replace the original
PC-relative addressing mode with indirect addressing through a
register which, via strength reduction, is now a kind of additional
loop index. This would be an admirable optimization except:
(1) The label LI%10 has been removed, but the definition of LD%10
(which requires LI%10 ) remains. The result is an error from the
assembler.
(2) The new address is 2 bytes too small. It looks as if GCC has
forgotten that, at least on the MC68000, PC-relative addressing
does not use the PC of the *beginning* of the instruction, but
rather the PC after one instruction fetch - i.e., 2 bytes *beyond*
the beginning of the instruction in which the PC-relative addressing
mode is used.
Lawrence G. Mayka
Aurora, Illinois
chinet!lmayk!lgm