From: colin@web.apc.org (Colin Plumb)
Subject: Gcc 2.2.2 (Amiga 68000) emitting suboptimal code
Organization: GNUs Not Usenet
Distribution: gnu
Date: Thu, 24 Dec 1992 09:40:00 GMT

I had an inner loop looking for a non-zero word in an array that
I thought was perfect for the 68000's DBcc instruction.  So I
coded it up and tried to compile.  H'm... no DBcc instruction.
I progressively wrote code closer and closer to raw assembler and
eventually ended up with the follwing (excerpt from a larger chunk
of code):
unsigned long
foo(unsigned long *p, unsigned short size)
{
	unsigned short len;
	unsigned long bits;

	len = size-1;
	do {
		bits = *p++;
	} while (!bits && len--);	/* STRONG hint to use dbne */
	if (bits)
		return bits;
	return 0;
}

Now, that last fiddling isn't really necessary; it's obviously equivalent
to "return bits;", but I wanted to see if Gcc was smart enough not to
re-test the bits variable after the dbne, and hoping it wouldn't be bright
enough to optimize that out.

If you read the 68000 data books, the condition on the while is
precisely what dbne is described as doing, except for comparing
--len with -1 instead of len-- with 0, but it's the same thing.
I was hoping to get something like:

.text
	.even
.globl _foo
_foo:
	movel sp@(4),a0
	movew sp@(10),d1
L1:
	movel a0@+,d0
	dbeq d1,L1
	bne L2
	moveq #0,d0
L2:
	rts

Running gcc, however:

Reading specs from gcc:compilers/amiga/2.2.2/specs
gcc version 2.2.2
 gcc:compilers/amiga/2.2.2/cpp -lang-c -v -undef -D__GNUC__=2 -Dmc68000 -Damiga -Damigados -DMCH_AMIGA -DAMIGA -D__mc68000__ -D__amiga__ -D__amigados__ -D__MCH_AMIGA__ -D__AMIGA__ -D__mc68000 -D__amiga -D__amigados -D__MCH_AMIGA -D__AMIGA -D__OPTIMIZE__ -Dmc68010 foo.c t:cc059344.i
GNU CPP version 2.2.2 (68k, MIT syntax)
 gcc:compilers/amiga/2.2.2/cc1 t:cc059344.i -quiet -dumpbase foo.c -O2 -version -o foo.s
GNU C version 2.2.2 (68k, MIT syntax) compiled by GNU C version 2.2.2.

Produces the following code:

#NO_APP
gcc2_compiled.:
.text
	.even
.globl _foo
_foo:
	movel d2,sp@-
	movel sp@(8),a0
	movew #65535,d0
	movew d0,d1
	addw sp@(14),d1
L2:
	movel a0@+,d2
	jne L3
	subqw #1,d1
	cmpw d1,d0
	jne L2
L3:
	tstl d2
	sne d0
	extw d0
	extl d0
	andl d2,d0
	movel sp@+,d2
	rts

The code between L2 and L3 is quite remarkable in how close to the operation
of dbne it is.  Other then the deficiency of not using dbne, I note the
following sub-optimalities with the code:
	- L3 should be positioned one instruction later.  At the target of
	  the jne, (cc0) is already set to correspond to d2, so it is not
	  necessary to re-test its value.
	- Instead of "cmpw d1,d0/jne L2" just before L3, perhaps "jcs L2"
	  would suffice.
	- d2 could have been spilled into a1 instead of the stack.

In my lavish praise of gcc, I've been saying I report as a bug any instance
where I could do better by hand without really massive trickery.  Thanks
for a great compiler, but this is such an example.

(BTW, the commercial compiler (Manx Aztec C 5.2) I have produces even
worse code, so don't think I'm exactly upset.)

Oh, yes, noted other places: gcc still does not do tail-recursion
optimisation even on calls to functions of no arguments, from functions
with no stack frames.  Sigh.  Oh, well.
-- 
	-Colin

Newsgroups: gnu.gcc.bug