[net.bugs.4bsd] Massive f77 fixes for subroutine argument temporary bugs

donn@sdchema.UUCP (04/08/84)

Here, as promised, are Bob Corbett's changes to f77 to prevent the
allocation of subroutine argument temporaries from trashing DO loop
limits and other things.  I have included the fixes to Bob's changes
which I have made, so if you are already running the changes from
Berkeley and Bob hasn't sent you the latest round of fixes, you will
want to use this code instead.

In any case, this supersedes the bug report I sent out titled 'Bug in
f77 loop optimizer generates incorrect code (serious!)'.  If you have
already installed my fix, you will need to remove it.  As a reminder,
here are the changes needed to remove my fix in exdo() in exec.c.  (All
source files that I'll be referring to are in /usr/src/f77/src/f77pass1.
Also, in each set of diffs, '*' marks old code and '-' marks new or
corrected code.)

---------------------------------------------------------------------------
*** /tmp/,RCSt1020046	Sat Apr  7 20:23:42 1984
--- exec.c	Fri Mar 23 14:50:26 1984
***************
*** 465,471
    if( CONSTLIMIT )
      ctlstack->domax = DOLIMIT;
    else
!     ctlstack->domax = (expptr) mkaltemp(dotype, PNULL);
  
    if( CONSTINCR )
      {

--- 447,453 -----
    if( CONSTLIMIT )
      ctlstack->domax = DOLIMIT;
    else
!     ctlstack->domax = (expptr) mktemp(dotype, PNULL);
  
    if( CONSTINCR )
      {
***************
*** 476,482
      }
    else
      {
!       ctlstack->dostep = (expptr) mkaltemp(dotype, PNULL);
        ctlstack->dostepsign = VARSTEP;
      }
  

--- 458,464 -----
      }
    else
      {
!       ctlstack->dostep = (expptr) mktemp(dotype, PNULL);
        ctlstack->dostepsign = VARSTEP;
      }
  
---------------------------------------------------------------------------

Here are the changes needed for the new set of fixes.  Be careful --
they are complicated.  Where there are long stretches of new code, it
is probably a good idea to clip out the diffs from this article with an
editor, remove the diff marks and install them directly into the file.

The file 'defs.h' needs a couple new external definitions:

---------------------------------------------------------------------------
*** /tmp/,RCSt1020106	Sat Apr  7 20:34:04 1984
--- defs.h	Fri Mar 23 14:50:15 1984
***************
*** 117,122
  extern flag anylocals;
  
  extern chainp templist;
  extern int maxdim;
  extern chainp holdtemps;
  extern struct Entrypoint *entries;

--- 133,140 -----
  extern flag anylocals;
  
  extern chainp templist;
+ extern chainp argtemplist;
+ extern chainp activearglist;
  extern int maxdim;
  extern chainp holdtemps;
  extern struct Entrypoint *entries;
---------------------------------------------------------------------------

The declarations of these variables are in init.c, and the code needed
to reset them is in procinit() in the same file:

---------------------------------------------------------------------------
*** /tmp/,RCSt1020131	Sat Apr  7 20:38:06 1984
--- init.c	Fri Mar 23 14:50:37 1984
***************
*** 112,117
  flag toomanyinit;
  ftnint curdtelt;
  chainp templist	= NULL;
  chainp holdtemps	= NULL;
  int dorange	= 0;
  struct Entrypoint *entries	= NULL;

--- 131,138 -----
  flag toomanyinit;
  ftnint curdtelt;
  chainp templist	= NULL;
+ chainp argtemplist = CHNULL;
+ chainp activearglist = CHNULL;
  chainp holdtemps	= NULL;
  int dorange	= 0;
  struct Entrypoint *entries	= NULL;
***************
*** 279,284
  for(cp = templist ; cp ; cp = cp->nextp)
  	free( (charptr) (cp->datap) );
  frchain(&templist);
  holdtemps = NULL;
  dorange = 0;
  nregvar = 0;

--- 300,308 -----
  for(cp = templist ; cp ; cp = cp->nextp)
  	free( (charptr) (cp->datap) );
  frchain(&templist);
+ for (cp = argtemplist; cp; cp = cp->nextp)
+   free((char *) (cp->datap));
+ frchain(&argtemplist);
  holdtemps = NULL;
  dorange = 0;
  nregvar = 0;
---------------------------------------------------------------------------

Subroutine argument temporaries need to be recycled at each statement
boundary (not at each call, unfortunately, since the code generator
moves the definitions of temporaries to the beginning of each
statement; the original Berkeley changes did this incorrectly).  This
requires a change in the production for 'stat' in gram.head:

---------------------------------------------------------------------------
*** /tmp/,RCSt1020164	Sat Apr  7 20:43:40 1984
--- gram.head	Fri Mar 23 22:46:53 1984
***************
*** 110,115
  				err("label already that of a format");
  			else
  				$1->labtype = LABEXEC;
  			}
  		}
  	| thislabel SINCLUDE filename

--- 126,136 -----
  				err("label already that of a format");
  			else
  				$1->labtype = LABEXEC;
+ 			}
+ 		  if(!optimflag)
+ 			{
+ 			argtemplist = hookup(argtemplist, activearglist);
+ 			activearglist = CHNULL;
  			}
  		}
  	| thislabel SINCLUDE filename
---------------------------------------------------------------------------

A similar change must occur in putopt() in optim.c:

---------------------------------------------------------------------------
*** /tmp/,RCSt1020183	Sat Apr  7 20:46:23 1984
--- optim.c	Fri Mar 23 22:48:42 1984
***************
*** 179,184
  		badthing("SKtype", "putopt", sp->type);
  		break;
  	}
  }
  
  

--- 195,208 -----
  		badthing("SKtype", "putopt", sp->type);
  		break;
  	}
+ 
+ 	/*
+ 	 * Recycle argument temporaries here.  This must get done on a
+ 	 *	statement-by-statement basis because the code generator
+ 	 *	makes side effects happen at the start of a statement.
+ 	 */
+ 	argtemplist = hookup(argtemplist, activearglist);
+ 	activearglist = CHNULL;
  }
  
  
---------------------------------------------------------------------------

Now comes the tough part.  A new routine mkargtemp() must be added in
proc.c following the code for mkaltmpn():

---------------------------------------------------------------------------
*** /tmp/,RCSt1020214	Sat Apr  7 20:52:40 1984
--- proc.c	Fri Mar 23 14:50:58 1984
***************
*** 1003,1008
  	fprintf(diagfile,"mkaltmpn new offset %d\n",
  		q->memoffset->constblock.const.ci);
  return(q);
  }
  ^L
  /* VARIOUS ROUTINES FOR PROCESSING DECLARATIONS */

--- 1013,1080 -----
  	fprintf(diagfile,"mkaltmpn new offset %d\n",
  		q->memoffset->constblock.const.ci);
  return(q);
+ }
+ 
+ 
+ 
+ /*  The following routine is a patch which is only needed because the	*/
+ /*  code for processing actual arguments for calls does not allocate	*/
+ /*  the temps it needs before optimization takes place.  A better	*/
+ /*  solution is possible, but I do not have the time to implement it	*/
+ /*  now.								*/
+ /*									*/
+ /*					Robert P. Corbett		*/
+ 
+ Addrp
+ mkargtemp(type, lengp)
+ int type;
+ expptr lengp;
+ {
+   ftnint leng;
+   chainp oldp, p;
+   Addrp q;
+ 
+   if (type == TYUNKNOWN || type == TYERROR)
+     badtype("mkargtemp", type);
+ 
+   if (type == TYCHAR)
+     {
+       if (ISICON(lengp))
+ 	leng = lengp->constblock.const.ci;
+       else
+ 	{
+ 	  err("adjustable length");
+ 	  return ((Addrp) errnode());
+ 	}
+     }
+ 
+   oldp = CHNULL;
+   p = argtemplist;
+ 
+   while (p)
+     {
+       q = (Addrp) (p->datap);
+       if (q->vtype == type
+ 	  && (type != TYCHAR || q->vleng->constblock.const.ci == leng))
+ 	{
+ 	  if (oldp)
+ 	    oldp->nextp = p->nextp;
+ 	  else
+ 	    argtemplist = p->nextp;
+ 
+ 	  p->nextp = activearglist;
+ 	  activearglist = p;
+ 
+ 	  return (q);
+ 	}
+ 
+       oldp = p;
+       p = p->nextp;
+     }
+ 
+   q = autovar(1, type, lengp);
+   activearglist = mkchain(q, activearglist);
+   return (q);
  }
  ^L
  /* VARIOUS ROUTINES FOR PROCESSING DECLARATIONS */
---------------------------------------------------------------------------

Finally, the routine putcall() in putpcc.c must be changed to use
mkargtemp() instead of mkaltemp().  This is what was causing the breakage
before, since putcall() was dipping into the pool of temporaries after
the point where that pool is supposed to be restricted.

---------------------------------------------------------------------------
*** /tmp/,RCSt1020263	Sat Apr  7 21:03:51 1984
--- putpcc.c	Fri Mar 23 22:51:59 1984
***************
*** 1267,1273
  int n, first;
  Addrp t;
  register expptr q;
! Addrp fval;
  int type, type2, ctype, qtype, indir;
  
  type2 = types2[type = p->vtype];

--- 1300,1306 -----
  int n, first;
  Addrp t;
  register expptr q;
! Addrp fval, mkargtemp();
  int type, type2, ctype, qtype, indir;
  
  type2 = types2[type = p->vtype];
***************
*** 1312,1318
  	{
  	if( ISICON(p->vleng) )
  		{
! 		fval = mkaltemp(TYCHAR, p->vleng);
  		n += 2;
  		}
  	else	{

--- 1345,1351 -----
  	{
  	if( ISICON(p->vleng) )
  		{
! 		fval = mkargtemp(TYCHAR, p->vleng);
  		n += 2;
  		}
  	else	{
***************
*** 1322,1328
  	}
  else if( ISCOMPLEX(type) )
  	{
! 	fval = mkaltemp(type, PNULL);
  	n += 1;
  	}
  else

--- 1355,1361 -----
  	}
  else if( ISCOMPLEX(type) )
  	{
! 	fval = mkargtemp(type, PNULL);
  	n += 1;
  	}
  else
***************
*** 1356,1362
  		if(indir)
  			putx(q);
  		else	{
! 			t = mkaltemp(qtype = q->headblock.vtype,
  				q->headblock.vleng);
  			putassign( cpexpr(t), q );
  			putaddr(t, NO);

--- 1389,1395 -----
  		if(indir)
  			putx(q);
  		else	{
! 			t = mkargtemp(qtype = q->headblock.vtype,
  				q->headblock.vleng);
  			putassign( cpexpr(t), q );
  			putaddr( cpexpr(t), NO );
***************
*** 1359,1365
  			t = mkaltemp(qtype = q->headblock.vtype,
  				q->headblock.vleng);
  			putassign( cpexpr(t), q );
! 			putaddr(t, NO);
  			putcomma(1, qtype, YES);
  			}
  		}

--- 1392,1398 -----
  			t = mkargtemp(qtype = q->headblock.vtype,
  				q->headblock.vleng);
  			putassign( cpexpr(t), q );
! 			putaddr( cpexpr(t), NO );
  			putcomma(1, qtype, YES);
  			}
  		}
---------------------------------------------------------------------------

That should keep you busy for a while...

Donn Seeley    UCSD Chemistry Dept.       ucbvax!sdcsvax!sdchema!donn
32 52' 30"N 117 14' 25"W  (619) 452-4016  sdcsvax!sdchema!donn@nosc.ARPA