[gnu.gcc.bug] '-fstrength-reduce' can handle 'switch' statements improperly

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