A simple non-portable expression tha

Gregory Smith greg at utcsri.UUCP
Tue May 6 05:13:14 AEST 1986


In article <972 at dataioDataio.UUCP> bright at dataio.UUCP (Walter Bright writes:
>In article <2609 at utcsri.UUCP> greg at utcsri.UUCP (Gregory Smith) writes:
>>However, I tried this ( using 16-bit short ints for I1,I2 ) on our
>>native vax compiler and on our 68K compiler. Both produced identical code
>>for (L+I1)+I2 and L+(I1+I2) and L+I1+I2: specifically, ((long)I1+L)+(long)I2.
>>I guess the a+b+c is recognized as a special case, and all three are widened
>>to a common width regardless of the original associativityy
>
>Shorts in C are always converted to ints before they are used. On the
>vax and most 68k compilers, ints are the same as longs. Therefore, this
>isn't any 'special case' recognized by the compiler.
>
>Different code for (L+I1)+I2 and L+(I1+I2) will only be generated if
>ints are smaller than longs.

You're quite right about the vax and 68K - since there's nothing wider than
an int, you can't get in trouble. This hadn't occurred to me. Maybe
someone with a PDP11 compiler could play with this and tell us what happens.

About the 'special case', though, let me quote 'A Tour through the UNIX
C Compiler', Dennis Ritchie ( about the PDP-11 compiler ):

       The *acommute* routine, called for associative and commutative
    operators, discovers clusters of the same operator at the top level
    of the current tree, and arranges them in a list: for
    `a+((b+c)+(d+f))' the list would be `a,b,c,d,e,f' [sic]. After each
    subtree is optimized, the list is stored in increasing difficulty
    of computation [...] the code generation algorithm works best when
    left operands are the difficult ones. [...] a constant is
    considered simpler than the address of a static or external, which
    is simpler than reference to a variable. This makes it easy to fold
    all the constants together, and also to merge together the sum of a
    constant and the address of a static or external [...].

       A special routine is invoked to handle sums of products. *Distrib*
    is based on the fact that it is better to compute `c1*c2*x + c2*y' as
    `c1*(c2*x+y)' and makes the divisibility tests required to assure the
    correctness of the transformation. This transformation is rarely
    possible with code directly written by the user, but it invariably
    occurs as a result  of the implementation of multidimensional arrays.

       Finally, *acommute* reconstructs a tree from the list of
    expressions which result.

Given this device, it wouldn't be hard, on a 16-bit machine, to detect
the presence of a long in a chained add, and to widen everything in the
list to long to avoid overflow problems.

Apparently there is no *Distrib* in the vax compiler:

The following code is generated for x=p[i];	int x,i,p[10];
	movl	_i,r0		; get i in register
	movl	_p[r0],_x	; x = mem( &p + i*4 )

The following code is generated for x=a[i][j]: int x,i,j,a[10][20]
( with -O option ):

	movl	_j,r0		; r0 = j
	mull3	$80,_i,r1	; r1 = 80*i
	addl2	$_a,r1		; r1 = &a + 80*i
	ashl	$2,r0,r0	; r0 = 4*j
	addl2	r0,r1		; r1 = &a + 80*i + 4*j
	movl	(r1),_x		; do the move

this *could* have been done as

	mull3	$20,_i,r1	; r1 = 20*i
	addl2	_j,r1		; r1 = 20*i + j
	movl	_a[r1],_x

if the compiler had rearranged &a+80*i+4*j as &a+4*(20*i+j).

Why wouldn't the vax compiler be at least as smart as the PDP compiler
for things like this? Especially in the presence of a '_a[r1]' addressing
mode with implicit scaling.
-- 
"Canabee be said2b or not2b anin tire b, if half thabee isnotabee, due2
somain chunt injury?" - Eric's Dilemma
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg



More information about the Comp.lang.c mailing list