[net.bugs.4bsd] [4bsd-f77 #29] F77 sometimes does improper code motion

4bsd-f77@utah-cs.UUCP (4.2 BSD f77 bug reports) (08/28/84)

From: Donn Seeley <donn@utah-cs.arpa>

Subject: F77 sometimes does improper code motion
Index:	usr.bin/f77/src/f77pass1/optloop.c 4.2BSD

Description:
	If a subroutine or function is passed as an EXTERNAL object to
	another routine, the code motion optimization in f77 fails to
	recognize that the EXTERNAL routine can modify its arguments.
	This bug was found by Jerry Berkman at Berkeley and fixed by a
	friend of his.

Repeat-By:
	The following program is courtesy Jerry Berkman.  Clip it out
	and compile it with the optimizer on:

	----------------------------------------------------------------
	c	bug in optimizer - does improper code motion:
	c				in sub1 ASSUMES iter not
	c				changed in call on sub
	c	same bug exists for functions - change 'call sub(iter)' to
	c		y = sub(iter)   and have sub2 return 0.0
		external sub2
		call sub1(sub2)
		end

		subroutine sub1( sub )
		external sub

		iter = -5
		do 10 i = 1, 10
		call sub( iter )
		if(iter.gt.0) go to 40
	10	continue
	40	print *, ' all done ', iter
		end

		subroutine sub2( iter )
		iter = iter + 1
		end
	----------------------------------------------------------------

	When you run it, it prints 'all done 5' instead of 'all done 1'
	like it should.

Fix:
	From looking at the assembly output, the problem is obvious --
	here is the loop in sub1 (prettied up some):

	----------------------------------------------------------------
		mnegl	$5,{iter}
		tstl	{iter}		# Compute iter.gt.0
		jleq	L9999
		movl	$1,r0		# r0 is 1 if iter.gt.0 is true
		jbr	L9998
	L9999:
		clrl	r0		# 0 otherwise
	L9998:
		movl	r0,-4(fp)
		movl	r0,r10
		movl	$1,{i}		# Start the loop
	L23:
		pushab	{iter}
		calls	$1,*4(ap)	# Call sub(iter)
		tstl	r10		# Use the result of iter.gt.0
		jneq	L27
		aobleq	$10,{i},L23
	L27:
	----------------------------------------------------------------

	The problem is that the computation 'iter.gt.0' is treated as a
	loop invariant and is moved in front of the loop.  The compiler
	doesn't realize that the subroutine call can alter the argument
	'iter' -- thus the loop is run the full 10 times instead of
	stopping when 'iter' reaches 1.

	One way of fixing this is to force the compiler to assume that
	all routines except those it explicitly knows are intrinsic
	can alter their arguments.  The change is in setsuses() in
	optloop.c:

	----------------------------------------------------------------
	*** /tmp/,RCSt1006165	Fri Jul 20 23:33:15 1984
	--- optloop.c	Thu Jul 19 11:53:31 1984
	***************
	*** 347,353
		    fatal("O8:  subprogram expected");
		  setsuses(p->exprblock.rightp);
		  setsuses(p->exprblock.vleng);
	! 	  if (p->exprblock.leftp->addrblock.vstg != STGEXT) break;
		  commonset = YES;
		  if (p->exprblock.rightp == NULL) break;
		  args = p->exprblock.rightp->listblock.listp;

	--- 362,368 -----
		    fatal("O8:  subprogram expected");
		  setsuses(p->exprblock.rightp);
		  setsuses(p->exprblock.vleng);
	! 	  if (p->exprblock.leftp->addrblock.vstg == STGINTR) break;
		  commonset = YES;
		  if (p->exprblock.rightp == NULL) break;
		  args = p->exprblock.rightp->listblock.listp;
	----------------------------------------------------------------

Donn Seeley    University of Utah CS Dept    donn@utah-cs.arpa
40 46' 6"N 111 50' 34"W    (801) 581-5668    decvax!utah-cs!donn