C "optimization" (4 of 8)

Dan Klein dvk at mi-cec.UUCP
Wed Feb 15 05:23:40 AEST 1984

This is a continuation of my diatribe on "C doesn't optimize, it neatens".
In this and other articles, I compare a true optimizing compiler (Bliss-32
running under VMS) to a code neatener (C running under BSD 4.1c).  Any and
all counterexamples are welcome.  However, this is NOT a comparison of the
languages.  Both C and Bliss have their good and bad points.  This is simply
a comparison of the code they generate.  As in all examples, the source
code and uncensored assembly code is presented.  In all examples, the C source
and Bliss source are as nearly identical as language differences permit.  I
have not taken advantage of any "tricks" to get either language to perform
better or worse than the other.  The optimizer was enabled for both languages.

		-Dan Klein, Mellon Institute, Pittsburgh	(412)578-3382

In this example I show how the compilers allocate local variables.  The
test code declares two local variables, "a", and "b".  By using flow analysis
it can be seen that the use of "a" and "b" does not overlap.  Now a really
"great" optimizer would not bother moving the constant values into the local
variables, and then pushing them on the stack (since it can also be seen that
the only use of the local variable is a place holder).  However, both compilers
can be forgiven in that it is possible for a debugger to tell you the values
of "a" and "b" if they occupy a location, while it is very difficult to make
a debugger smart enough to look on the stack during a partially executed
routine call.  The comparison:
	1) C is not smart enough to recognize that the use of the variables
overlaps, and instead allocates two locations (on the stack) for them.  Bliss
on the other hand recognizes this fact, and shares a location for both the
variables.  DON'T tell me C does it so the debugger can distinguish between
the two variables.  If the VMS debugger is smart enough to tell the difference,
then so can the Unix debuggers.
	2) C allocates the variables on the stack, while Bliss chooses to use
register 0.  Even if Bliss had used two registers, it still could have used
R1 and R0.  C should also, but instead it plods around playing with the stack.
The C code is larger, and also substantially slower.
external routine alpha;			|	extern  alpha();
routine test(parm) : NoValue =		|	test()
	begin				|	{
	local a,b;			|	    int a, b;
	a = 2;				|	    a = 2;
	alpha(.a);			|	    alpha(a);
	b = 5;				|	    b = 5;
	alpha(.b);			|	    alpha(b);
	end;				|	}
	.TITLE  FOO			|		.data
					|		.text
	.EXTRN  ALPHA			|	LL0:	.align	    1
					|		.globl  _test
	.PSECT  $CODE$,NOWRT,2		|		.set	L13,0x0
					|		.data
TEST:	.WORD	^M<>			|		.text
	MOVL	#2, R0			|	_test:  .word	  L13
	PUSHL	R0			|		subl2	$8,sp
	CALLS	#1, W^ALPHA		|		movl	$2,-4(fp)
	MOVL	#5, R0			|		pushl	-4(fp)
	PUSHL	R0			|		calls	$1,_alpha
	CALLS	#1, W^ALPHA		|		movl	$5,-8(fp)
	RET				|		pushl	-8(fp)
					|		calls	$1,_alpha
					|		ret

More information about the Comp.lang.c mailing list