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