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