[net.bugs.4bsd] [4bsd-f77 #37] f77 sometimes rewrites register variables incorrectly

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

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

Subject: f77 sometimes rewrites register variables incorrectly
Index:	usr.bin/f77/src/f77pass1/regalloc.c 4.2BSD

Description:
	When an f77 subroutine is passed another subroutine as an
	argument (I'll call the latter 'EXTERNAL' subroutines although
	this is not entirely accurate), the compiler sometimes fails to
	keep straight the information that is in memory and the
	information that has been written out to register when
	processing calls to the EXTERNAL subroutine.  The effect is
	that when an EXTERNAL subroutine is called from inside a loop,
	some of its parameters may appear to have the value they had
	outside the loop.  This bug was found and fixed by Jerry
	Berkman and friends.

Repeat-By:
	This is really several bugs with a common nature; the following
	two programs from Jerry Berkman illustrate different features of
	the bugs.  Compile this program with the optimizer on:

	----------------------------------------------------------------
	c	in loop in d01anw, i is in a register, but in computing x(i-1),
	c		the value of i from storage is used
		
		double precision a, b
		external dfct
		a = 1.0d0
		b = 2.0d0
		call d01anw(dfct, a, b )
		end
		
		double precision function dfct( dx )
		double precision dx
		dfct = dx
		end
		
	      subroutine d01anw(f, a, b)
	      double precision a, b, f
	      external f
	      double precision centre, hlgth, fval(8), x(8)
	      data x / 0.1d0, 0.2d0, 0.3d0, 0.4d0, 0.5d0, 0.6d0, 0.7d0, 0.8d0 /

	      centre = (b+a)
	      hlgth = (b-a)

	      do 260 i=2,8
		   fval(i) = f(hlgth*x(i-1)+centre)
	  260 continue

	      print 8010, fval
	8010  format(4f8.4)
	      end
	----------------------------------------------------------------

	When you run the program you get the result:

	----------------------------------------------------------------
	  0.      3.0000  3.0000  3.0000
	  3.0000  3.0000  3.0000  3.0000
	----------------------------------------------------------------

	But you should see instead:

	----------------------------------------------------------------
	  0.      3.1000  3.2000  3.3000
	  3.4000  3.5000  3.6000  3.7000
	----------------------------------------------------------------

	The second program is more of the same.  Compile it with the
	optimizer on:

	----------------------------------------------------------------
	c		when calling subroutine which is an argument,
	c		optimizer sometimes forgets to transfer arguments to
	c		memory (if in registers)

		external sub
		data ia/1/, ib/2/
		call d01anw(sub, ia, ib )
		end
		
		subroutine sub( ii )
		ii = 2 * ii
		end
		
	      subroutine d01anw(subr, ii, jj )
	      external subr
	      integer fval(4)

	      ic = (jj+ii)
	      id = (jj-ii)

	      do 260 i=1,4
		   call subr( ic )
		   fval(i) = ic * ( id + ic )
	  260 continue
	      print *, fval
	      end
	----------------------------------------------------------------

	If you didn't install the previous fix for EXTERNAL subroutines
	('F77 sometimes does improper code motion'), then you get the
	following when you run the program:

	----------------------------------------------------------------
	  24  48  96  192
	----------------------------------------------------------------

	If you were conscientious and installed the earlier fix, the
	output is still wrong:

	----------------------------------------------------------------
	  12  12  12  12
	----------------------------------------------------------------

	The answer you want is:

	----------------------------------------------------------------
	  42  156  600  2352
	----------------------------------------------------------------

Fix:
	There are a couple problems here.  One is that variables are
	not being updated from register when they need to be.  The
	other, related problem is that f77 is making a distinction
	between subroutines that can change their arguments and
	subroutines that can't, and it mistakenly lumps EXTERNAL
	procedures with the latter group.  These problems are easily
	fixed by adding a missing call to regwrite() and changing
	all tests of the form 'ap->vstg == STGEXT' to 'ap->vstg !=
	STGINTR'; this last change has the effect of making f77
	think that any subroutine other than an intrinsic subroutine
	may alter its arguments, and completes the change that was
	started on with the earlier 'improper code motion' article.
	The changes are in scancall(), countrefs() and regwrite()
	in regalloc.c:

	----------------------------------------------------------------
	*** /tmp/,RCSt1028628	Mon Aug 20 16:43:57 1984
	--- regalloc.c	Wed Aug 15 17:44:14 1984
	***************
	*** 1100,1106
	  
	    if (ep->rightp == NULL) return;
	  
	!   if (lhs->vstg == STGEXT)
	      {
		args = ep->rightp->listblock.listp;
		for (; args; args = args->nextp)

	--- 1103,1109 -----
	  
	    if (ep->rightp == NULL) return;
	  
	!   if (lhs->vstg != STGINTR)
	      {
		args = ep->rightp->listblock.listp;
		for (; args; args = args->nextp)
	***************
	*** 1173,1179
		  countrefs(p->exprblock.leftp->addrblock.vleng);
		  countrefs(p->exprblock.leftp->addrblock.memoffset);
	  
	! 	  if (p->exprblock.leftp->addrblock.vstg == STGEXT)
		    {
		      if (!commonunusable)
			if (linearcode)

	--- 1176,1182 -----
		  countrefs(p->exprblock.leftp->addrblock.vleng);
		  countrefs(p->exprblock.leftp->addrblock.memoffset);
	  
	! 	  if (p->exprblock.leftp->addrblock.vstg != STGINTR)
		    {
		      if (!commonunusable)
			if (linearcode)
	***************
	*** 1342,1348
		  ap = (Addrp) p->exprblock.leftp;
		  regwrite(sp, ap->vleng);
		  regwrite(sp, ap->memoffset);
	! 	  if (ap->vstg == STGEXT)
		    {
		      if (linearcode)
			{

	--- 1345,1351 -----
		  ap = (Addrp) p->exprblock.leftp;
		  regwrite(sp, ap->vleng);
		  regwrite(sp, ap->memoffset);
	! 	  if (ap->vstg != STGINTR)
		    {
		      if (linearcode)
			{
	***************
	*** 1416,1421
				  ap->vstg = STGPREG;
				  ap->memno = regnum[i];
				}
			  }
		    }
		  return;

	--- 1419,1428 -----
				  ap->vstg = STGPREG;
				  ap->memno = regnum[i];
				}
	+ 		  }
	+ 		else
	+ 		  {
	+ 		    regwrite(sp, args->datap);
			  }
		    }
		  return;
	----------------------------------------------------------------

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