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