Google
 

Trailing-Edge - PDP-10 Archives - FORTRAN-10_V7wLink_Feb83 - doalc.bli
There are 12 other files named doalc.bli in the archive. Click here to see a list.
!THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
!  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.

!COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1972, 1983
!AUTHOR: NORMA ABEL/MD/DCE/JNG/TFV/AHM/TGS

MODULE DOALC(RESERVE(0,1,2,3),SREG=#17,VREG=#15,FREG=#16,DREGS=4)=
BEGIN


GLOBAL BIND DOALCV = 7^24 + 0^18 + #1505;	! Version Date:	15-Mar-82

%(

***** Begin Revision History *****

95	-----	-----	PUT CHECK INTO "ALCDOS" SO THAT THE FN-VAL RETURN
			REGISTER WILL NEVER BE USED FOR A DO LOOP INDEX OR COUNT
96	-----	-----	FIX STCMSFN TO RESET NAME TO IDTAB PRIOR TO
			EACH CALL TO TBLSEARCH
97	-----	-----	CHANGE REFERENCES RO PROEPITYP AND PROGNAME
98	-----	-----	SET ENTNOCOPYFLG ON ENTRY ARGS THAT AR NOT
			FORMAL ARRAYNAMES AND HAVE NOALLOC SET
99	-----	-----	SET COMPLEXITY FIELD IN DO STMNTS
100	-----	-----	DO NOT ALLOCATE TEMP TO SAVE REG 16 IF REG
			16 WONT BE SAVED
101	-----	-----	IN "ASNFNVAL" - IF THIS STMNT IS TE LAST STMNT
			OF A DO LOOP, CANNOT TREAT IT AS ASSIGNMENT OF FN VAL
102	-----	------	IF A STMNT FN PARAM IS NEVER REFERENCED, DONT
				PICK IT UP (SET FLAG "ENTNOCOPYFLG")
103	-----	-----	DO NOT ALLOCATE A COMMON SUBEXPRESSION ON A DO STMNT
			TO THE REG THAT THE INDEX WILL GO INTO
104	-----	-----	THE TEST FOR ALLOCATING A DO LP CT
			SHOULD NOT BE INSIDE THE CONDITIONAL ON STEP SIZE
			ALSO, THE TEST FOR IMMED CNST SHOULD BE MADE
105	-----	-----	FOR STMNT FNS, SHOULD SET FTEMP TO NXTTTMP
			WHENEVER ANY QTEMPS HAVE BEEN USED
			IN THE PROGRAM AT ALL (CANNOT TELL THAT THIS SFN
			USED ANY QTEMPS SIMPLY BY SEEING IF THE VAL OF LSTLNK
			CHANGED- SINCE THE PREVIOUS SFN MIGHT HAVE
			CALLED NXTTMP AND THEN THIS SFN WILL SIMPLY
			USE THE QTEMP THAT WAS ALREADY CREATED)
106	323	16729	USE .A00NN FOR NAME OF TEMPORARY USED  TO SAVE
			REGISTERS IN PROLOGUE OF A FUNCTION, (MD)
107	332	17045	IN LPIXSUB PROPAGATE REGCONTENTS TO ASSIGN
			STATEMENTS WITH SUBSCRIPTED ARGUMENTS., (DCE)
108	426	18816	DON'T ALLOCATE TEMP STORAGE IN STMNT FN'S FOR
			DOUBLE PRECISION & COMPLEX PARAMETERS - IT
			DOESN'T SOLVE ANYTHING. SET FNCALLSFLG INSTEAD., (JNG)

***** Begin Version 5B *****

109	726	28283	KA DOUBLE PRECISION AND COMPLEX REALLY DO
			NEED TO BE ALLOCATED (FIX EDIT 426), (DCE)

***** Begin Version 6A *****

1163	TGS	1-Jul-82	20-17540
	If /DEBUG:INDEX was specified, bypass optimization that substitutes
	a regcontents node using the function return reg for the left hand side
	of an assignment statement to the function variable.

***** Begin Version 7 *****

110	1245	TFV	3-Aug-81	------
	Redo ALCTEMP; it is now called ALCAVARS.  Have it allocate the
	.A variables and list them.

111	1274	TFV	20-Oct-81	------

	Fix ALCSFN  to  set LASTSFNQ  and  QSFNMAX so  that  the  .Qnnnn
	variables used by  statement functions are  not reused by  other
	statements.

112	1455	TFV	5-Jan-82	------
	Rewrite  STCMSFN  and  ALCSFN  to  handle  character   statement
	functions.  A character statement function is turned into either
	a call to CHSFN.  (the subroutine form of CHASN.)  or a call  to
	CHSFC.  (the subroutine form of CONCA.).  CHSFC.  is used if the
	character expression has concatenations at its top level, CHSFN.
	is used for all other character expressions.

1474	TFV	15-Mar-82
	Add  a  new  argument  to  CMPFNARGS.   Character  concatenation
	expressions also use  CMPFNARGS, the first  argument is not  yet
	allocated for concatenations so it must be ignored by CMPFNARGS.

1505	AHM	12-Mar-82
	Speed up the compiler by changing a LSH -3 followed by a LSH 6
	to a LSH 3 in macro TNAME in routine ALCAVARS.

***** End Revision History *****

)%

SWITCHES NOLIST;
REQUIRE FIRST.BLI;
REQUIRE TABLES.BLI;
REQUIRE REQREL.BLI;
SWITCHES LIST;

FORWARD
	STCMDO,
	ALCDOSTMT,
	ALCDOEND(1),
	STCMRETURN,
	ALCRETURN,
	HDRTMP,
	ALCAVARS,
	STCMSFN,
	ALCSFN,
	STCMSUB,
	LPIXSUB,
	ALCENTRY,
	ALCENLIST(1),	! Routine to determine which registers to use to
			! pick up the params of a function,  subroutine,
			! or statement function
	ARGSIZREST(1),
	FNVALCHK,
	FNVLCH1,
	ASNFNVAL;	! Routine to check whether the statement pointed
			! to by cstmnt  assigns the  function value  and
			! directly precedes a return

EXTERNAL
	ADDREGCANDATE,	! Routine  to  tell  the  basic  block  register
			! allocator that the value  of a given  variable
			! can be left in a register.
	AFREEREG,	! Routine to select  a free register  to use  if
			! possible.  It will  not select  a register  of
			! future use in this basic block.
	ALCASMNT,	! Routine to do register allocation for an assignment
%1455%	ALCCALL,	! Routine to do register allocation for a call
	ALCCMNSB,
	ALCINREG,
	ALOCONST,
	CDONODE,
	CGERR,		! Routine for internal compiler error detected
	CHOSEN,
	CLOBBREGS,	! Global containing  a  bit  pattern  indicating
			! which  registers   are   clobbered   in   this
			! subroutine (a bit  is 1  if the  corresponding
			! register gets clobbered)
%1455%	CMPFNARGS,	! Routine to find complexity of function arguments
	CORMAN,
	CSTMNT,
	DBLMODE,
	OBJECTCODE DOWDP,
	ENTRY,
	FNTMP,
	GBSYCT,
	GBSYREGS,
	GLOBREG,
	HDRFLG,
%1245%	HEADCHK,	! Routine to check the amount of space left on a
			! listing page
	ITMCT,
	IOSUBSTITUTE,
	LASTONE,
%1274%	LASTQ,		! Pointer to the  last .Qnnnn  variable used  by
			! the current statement.
%1274%	LASTSFNQ,	! Pointer to the  last .Qnnnn  variable used  by
			! statement  functions.  The  .Qnnnn   variables
			! between QANCHOR and LASTSFNQ can not be reused
			! by other statements.
	LEAFSUBSTITUTE,
%1245%	LISTSYM,	! Routine to list a symbol in the listing
	LOWLOC,
%1245%	LSTHDR,		! Routine to output a header to the listing
%1245%	LSTOUT,
	MAKEPR,
	MAKRC0,		! Routine to build a regcontents 0 node
	MISCIO,
	NAME,
	PREV,
	PROGNAME,
%1274%	QMAX,		! Maximum size of .Q space for all statements
	QQ,
%1274%	QSFNMAX,	! Maximum size  of .Q  space used  by  statement
			! functions.
	REGCLOBB,	! Routine to tell the basic block allocator that
			! the  previous  contents  of  a  register   are
			! clobbered
	RGTOU1,
	SAVEREG,	! Routine to remember that  a given variable  is
			! in a given register
	SETCOMPLEXITY,
	SORCPTR,
	SPECCASE,
	SSIZTMP,
	STBSYR,		! Bit pattern  indicating  which  registers  are
			! legal to use for this statement
	STCMASMNT,
	STCMCSB,
	STRGCT,
	SYMTYPE,
	TBLSEARCH,
%1245%	TCNT,
	TREEPTR;


GLOBAL
	ASVCT,		! Number of  assignment statements  that  assign
			! the  value  of  this  function  and   directly
			! precede a return statement.
	RETNCT;		! Number of return statements in the program

GLOBAL ROUTINE STCMDO=
BEGIN
	!PERFORM COMPLEXITY CALCULATIONS FOR DO LOOP
	!THE GLOBAL CSTMNT POINTS AT THE ENCODED SOURCE FOR THE
	!DO STATEMENT.

	MAP BASE CSTMNT;

	OWN
		PEXPRNODE IXSYM,
		PEXPRNODE DOCTL,
		PEXPRNODE PEXPR,
		PEXPRNODE DOINITL,
		PEXPRNODE DOSTEPSIZ;

	DOSTEPSIZ_.CSTMNT[DOSSIZE];
	IXSYM_.CSTMNT[DOSYM];
	DOCTL_.CSTMNT[DOLPCTL];
	DOINITL_.CSTMNT[DOM1];

	%(***FOR AN AOBJN LOOP, ALLOCATE CORE FOR THE AOBJN CONSTANT***)%
	IF .CSTMNT[FLCWD] THEN ALOCONST(.CSTMNT[DOLPCTL])
	ELSE
	BEGIN
		IF .DOCTL[OPRCLS] NEQ DATAOPR THEN
		BEGIN
			TREEPTR_.DOCTL;
			CSTMNT[SRCCMPLX]_SETCOMPLEXITY()
				+ (IF .IXSYM[DBLFLG]
				   THEN 2	!2 REGS USED FOR DP INDEX
				  ELSE 1);	!1 REG FOR INDEX OTHERWISE

		END;

		%(***IF THE INITIAL VAL IS A CONSTANT DECIDE WHETHER TO TREAT IT IMMED
			OR TO ALLOCATE CORE FOR IT***)%
		IF .DOINITL[OPR1] EQL CONSTFL
		THEN
		BEGIN
			IF IMMEDCNST(DOINITL)
			THEN
			%(***IF INTIAL VAL IS AN IMMEDIATE SIZE CONSTANT***)%
			BEGIN
				IF .DOINITL[VALTP1] EQL INTEG1 AND .DOINITL[CONST2] LSS 0
				THEN
				%(***FOR NEGATIVE INTEGERS - TO HANDLE IMMED MODE, MUST
					USE THE ABSOLUTE VAL PICKED UP NEGATED***)%
				BEGIN
					CSTMNT[INITLNEG]_1;
					CSTMNT[DOM1]_MAKECNST(.DOINITL[VALTYPE],0,-.DOINITL[CONST2]);
				END;
				CSTMNT[INITLIMMED]_1;
			END
			ELSE
			%(***IF INITIAL VAL IS A CONSTANT NOT IMMED, ALLOCATE CORE FOR IT***)%
			ALOCONST(.DOINITL);
		END;

		%(***IF THE STEP SIZE IS A CONSTANT, DECIDE WHETHERTO USE IT IMMED OR ALLOCATE CORE
			FOR IT*****)%
		IF .DOSTEPSIZ[OPR1] EQL CONSTFL AND (NOT .CSTMNT[SSIZONE]
		OR .DOSTEPSIZ[VALTYPE] EQL DOUBLPREC)
		THEN
		BEGIN
			IF IMMEDCNST(DOSTEPSIZ)
			THEN
			BEGIN
				IF .DOSTEPSIZ[VALTP1] EQL INTEG1 AND .DOSTEPSIZ[CONST2] LSS 0
				THEN
				BEGIN
					CSTMNT[SSIZNEGFLG]_1;
					CSTMNT[DOSSIZE]_MAKECNST(.DOSTEPSIZ[VALTYPE],0,-.DOSTEPSIZ[CONST2]);
				END;
				CSTMNT[SSIZIMMED]_1;
			END
			ELSE
			ALOCONST(.DOSTEPSIZ);
		END;


		%(***IF THE CONTROL EXPR IS A CONSTANT, NOT IMMEDIATE SIZE,
			ALLOCATE CORE FOR IT***)%
		IF .DOCTL[OPR1] EQL CONSTFL
		THEN
		BEGIN
			IF IMMEDCNST(DOCTL)
			THEN
			BEGIN
				 CSTMNT[CTLIMMED]_1;
				IF .DOCTL[CONST2] LSS 0		!FOR NEG IMMED
				THEN
				BEGIN
					CSTMNT[CTLNEG]_NOT .CSTMNT[CTLNEG];
					!USE MOVNI OF THE POSITIVE CONST
					CSTMNT[DOLPCTL]_MAKECNST(.DOCTL[VALTYPE],0,-.DOCTL[CONST2]);
					DOCTL_.CSTMNT[DOLPCTL];
				END;
			END
			ELSE ALOCONST(.DOCTL)
		END;
	END;




	!MAKE EXTRA SURE THAT NEDSMATRLZ IS SET IF THE DO LOOP
	!INDEX IS A DOUBLE WORD QUANTITY.
	PEXPR_.CSTMNT[DOSYM];
	IF .PEXPR[DBLFLG] THEN CSTMNT[NEDSMATRLZ]_1;


	!COMPUTE COMPLEXITY OF COMMON SUB-EXPRESSIONS
	STCMCSB();


	!DEFINE THE REG TO BE USED FOR THE LOOP INDEX. THIS MAY BE CHANGED
	! BY THE GLOBAL ALLOCATOR (MUST SPECIFY IT HERE SO CAN SUBSTITUTE
	! REGCONTENTS NODES FOR REFS TO THE VAR)
	CSTMNT[DOIREG]_DOIXREG;


	!IF THE LOOP INDEX OF THIS LOOP WILL LIVE IN A REGISTER, SET A GLOBAL
	! TO ENABLE SUBSTITUTION OF "REGCONTENTS" NODES FOR ALL OCCURRENCES OF
	! THAT INDEX INSIDE OF THE LOOP
	IF NOT .CSTMNT[NEDSMATRLZ] AND NOT .CSTMNT[MATRLZIXONLY] THEN
	BEGIN
		!SET UP VARIABLES AND FIELDS NECESSARY FOR
		!SUBSTITUTION OF REGCONTENTS NODES.
		CDONODE_.CSTMNT;
		DOWDP[DOREGPTR]_.CSTMNT[DOIREG];
		PEXPR_MAKEPR(REGCONTENTS,0,INDEX,0,.CSTMNT[DOSYM]);
		PEXPR[INREGFLG]_1;
		PEXPR[TARGADDR]_.DOWDP[DOREGPTR];
		PEXPR[TARGTAC]_.DOWDP[DOREGPTR];
		DOWDP[DOREGPTR]_.PEXPR;
		IF .CSTMNT[FLCWD] THEN
		BEGIN
			SPECCASE_2;	!THIS FLAG TELLS "LEAFSUB" TO SET THE
					! IMMEDFLG ABOVE THE REGISTER SUBSTITUTED FOR LOOP INDEX
			PEXPR[VALTYPE]_INDEX;
		END ELSE
		BEGIN
			SPECCASE_0;	!IF "FLCWD" WAS NOT SET IN THE DO NODE, DO
					! NOT WANT TO SET IMMEDFLG OVER REFS TO LOOP INDEX
			DOSTEPSIZ_.CSTMNT[DOSYM];
			PEXPR[VALTYPE]_.DOSTEPSIZ[VALTYPE];
		END;
	END

END;	! of STCMDO


GLOBAL ROUTINE ALCDOSTMT=
BEGIN
	REGISTER PEXPRNODE IXSYM;	!SYM TAB ENTRY FOR LOOP INDEX

	MAP
		PEXPRNODE CSTMNT,
		PEXPRNODE TREEPTR;

	!REGISTER ALLOCATION FOR A DO STATEMENT
	!CSTMNT: POINTS AT DO STATEMENT
	LOCAL SSIZPT;
	LOCAL PEXPRNODE DOCEXPR;
	MAP BASE SSIZPT;


	!DONT USE THE FN RETURN REG FOR THE IX OR CT OF A DO LOOP
	STBSYR_REMRETREG(.STBSYR);
	STRGCT_ONESCOUNT(.STBSYR);



	IXSYM_.CSTMNT[DOSYM];	!PTR TO SYM TAB ENTRY FOR LP IX

	IF NOT BITSET(.STBSYR,.CSTMNT[DOIREG])	!IF THE REG PREVIOUSLY ASSIGNED
							! TO BE USED FOR THE LOOP INDEX IS NOT AVAILABLE
		AND NOT .CSTMNT[IXGALLOCFLG]	! AND THAT REG WAS NOT ASSIGNED BY THE GLOBAL REG ALLOCATOR
	THEN
	BEGIN
		IF NOT .CSTMNT[NEDSMATRLZ] AND NOT .CSTMNT[MATRLZIXONLY]	!IF HAVE ALREADY
							! SUBSTITUTED REGCONTENTS NODES FOR THE LOOP INDEX
		THEN CGERR();	! HAVE AN INTERNAL COMPILER ERROR

		CSTMNT[DOIREG]_		!PICK ANOTHER REG TO USE
			AFREEREG(.STBSYR,.CSTMNT[SRCSAVREGFLG],.IXSYM[DBLFLG])
	END;


	!ALLOCATE COMMON SUB-EXPRESSIONS FIRST
	IF BITSET(.STBSYR,.CSTMNT[DOIREG])	!DO NOT WANT TO LEAVE A COMMON
	THEN					! SUB IN THE REG TO BE USED FOR THE LOOP INDEX
	BEGIN
		STBSYR_CLRBIT(.STBSYR,.CSTMNT[DOIREG]);	!TAKE THAT REG OUT OF
		STRGCT_.STRGCT-1;			! THE SET OF AVAILABLE REGS TEMPORARILY
		ALCCMNSB();
		STBSYR_SETBIT(.STBSYR,.CSTMNT[DOIREG]);	!THEN PUT IT BAK (MAY HAVE TAKEN
							!  SOME OTHERS OUT IN THE MEANTIME)
		STRGCT_.STRGCT+1;
	END
	ELSE	!IF THAT REG WAS UNAVAILABLE ANY WAY (BECAUSE IT WAS GLOBALLY ALLOCATED)
	ALCCMNSB();


	%(***GET PTR TO EXPRESSION FOR LOOP CTL CT***)%
	DOCEXPR_.CSTMNT[DOLPCTL];

	TREEPTR_.DOCEXPR;

	CLOBBREGS_SETBIT(.CLOBBREGS,.CSTMNT[DOIREG]);	!THE REG TO BE USED FOR THE LOOP INDEX
					! WAS DETERMINED PREVIOUSLY (EITHER BY THE GLOBAL ALLOCATOR
					! OR IN COMPLEXITY PASS). SET BIT INDICATING THAT THAT
					! REG HAS BEEN CLOBBERED
	IF .IXSYM[DBLFLG]	!IF INDEX TAKES 2 REGS
	THEN CLOBBREGS_SETBIT(.CLOBBREGS,.CSTMNT[DOIREG]+1);


	IF .CSTMNT[FLCWD] THEN		!NICE AOBJN CASE
	CSTMNT[DOCREG]_.CSTMNT[DOIREG]
	ELSE
	!PERFORM ALLOCATION FOR THE CALCULATION OF THE LOOP CTL COUNT
	BEGIN
		REGISTER RA; !REG TO USE FOR LOOP CTL
		STBSYR_CLRBIT(.STBSYR,.CSTMNT[DOIREG]);	!DO NOT USE THE REG CONTAINING THE
							! THE LOOP INDEX IN CALCULATING THE CTL COUNT
		IF .IXSYM[DBLFLG]	!IF INDEX TAKES 2 REGS
		THEN STBSYR_CLRBIT(.STBSYR,.CSTMNT[DOIREG]+1);

		IF .CSTMNT[IXGALLOCFLG]		!IF THE GLOBAL OPTIMIZER HAS DECIDED TO
						! LEAVE THE INDEX OF THIS LOOP IN A REG
			AND NOT .CSTMNT[MATRLZCTLONLY]	! AND HAS ALSO DECIDED TO LEAVE THE CTL-COUNT
						! IN A REG THROUGHOUT THE LOOP
		THEN STBSYR_CLRBIT(.STBSYR,DOIXREG);	! DO NOT PUT THE COUNT INTO THE
						! REG THAT WILL BE USED FOR THE INDICES OF THE INNER DO LOOPS


		RA_AFREEREG(.STBSYR,FALSE,FALSE);	!GET A REG TO USE FOR THE CTL COUNT
		IF .TREEPTR[OPRCLS] NEQ DATAOPR THEN
		BEGIN
			ALCINREG(.RA,.STBSYR,.STRGCT-1);

			%(***IF POSSIBLE USE THE SAME REG INTO WHICH THE CTL EXPR
				WAS CALCULATED FOR THE LOOP CTL REG***)%
			IF .DOCEXPR[INREGFLG] AND NOT .DOCEXPR[ALCRETREGFLG]
			THEN
			BEGIN
				CSTMNT[DOCREG]_.DOCEXPR[TARGTAC];
				CSTMNT[CTLSAMEFLG]_1;
			END
			ELSE
			BEGIN
				RA_RGTOU1(.CSTMNT,.DOCEXPR,.RA,.STBSYR);
				CSTMNT[DOCREG]_.RA;
			END
		END ELSE
			CSTMNT[DOCREG]_.RA;

		!MAKE SURE THE STEP CONSTANT IS ALLOCATED
		SSIZPT_.CSTMNT[DOSSIZE];
		IF .SSIZPT[OPR1] EQL CONSTFL THEN
				ALOCONST(.SSIZPT);
		CLOBBREGS_SETBIT(.CLOBBREGS,.CSTMNT[DOCREG]);
	END;


	%(***IF EITHER LOOP INDEX OR CTL VAR WILL BE MAINTAINED IN A REG THROUGHOUT THE
		THE LOOP, TAKE THOSE REGS OUT OF THE SET OF FREE REGS***)%
	IF NOT .CSTMNT[NEDSMATRLZ] AND NOT .CSTMNT[MATRLZIXONLY]	!IF LP INDEX IS IN A REG
	 THEN
	BEGIN
		REGISTER RI;	!REG USED FOR THE LOOP INDEX
		RI_.CSTMNT[DOIREG];		!REG USED TO HOLD THE  INDEX
		GBSYREGS_CLRBIT(.GBSYREGS,.RI);	!TAKE LOOP INDEX REG OUT OF SET 

						!AVAILABLE FOR LOCAL USE

		IF .IXSYM[DBLFLG] THEN		!IF IX IS DOUBLE-WD, MUST TAKE OUT
		GBSYREGS_CLRBIT(.GBSYREGS,.RI+1); !NEXT REG ALSO

	END;

	IF NOT .CSTMNT[NEDSMATRLZ] AND NOT .CSTMNT[MATRLZCTLONLY]	!IF CTL VAR IN A REG
	THEN
	GBSYREGS_CLRBIT(.GBSYREGS,.CSTMNT[DOCREG]);	!TAKE OUT REG USED FOR LOOP CTL

	GBSYCT_ONESCOUNT(.GBSYREGS);

END;	! of ALCDOSTMT


GLOBAL ROUTINE ALCDOEND(TLAB)=
BEGIN

	!RETURN REGISTER TO GBSYREGS IF WE ARE ENDING AN INNER DO

	OWN PEXPRNODE DOVAR;		!LOOP INDEX VARIABLE
	OWN RA;				!REG USED TO HOLD LOOP INDEX VAR
	REGISTER TMP,CURDO;
	MAP BASE TLAB:CURDO:TMP;

	IF .TLAB[SNDOLVL] EQL 0 THEN RETURN;	!NO DO'S END HERE

	TMP_.TLAB[SNDOLNK];
	CURDO_.TMP[LEFTP];		!THIS POINTS AT FIRST DO IN LIST

	IF NOT .CURDO[NEDSMATRLZ] AND NOT .CURDO[MATRLZIXONLY]	!IF LOOP INDEX WAS MAINTAINED IN A REG
	THEN				!RETURN THAT REG TO SET OF FREE REGS
	BEGIN
		DOVAR_.CURDO[DOSYM];	!LOOP INDEX VARIABLE
		RA_.CURDO[DOIREG];		!REG USED TO HOLD LOOP INDEX VAR
		GBSYREGS_SETBIT(.GBSYREGS,.RA);		!RETURN THIS REG TO SET OF AVAILABLE REGS
		IF .DOVAR[DBLFLG]	!FOR LOOP INDEX DP, MUST RETURN THE REG AFTER RA
		THEN			! TO THE SET OF FREE REGS
		GBSYREGS_SETBIT(.GBSYREGS,.RA+1);

	END;

	IF NOT .CURDO[NEDSMATRLZ] AND NOT .CURDO[MATRLZCTLONLY]	!IF CTL VAR WAS IN A REG THROUGHOUT
						! THE LOOP, RETURN THAT REG TO SET OF FREE REGS
	THEN
	 GBSYREGS_SETBIT(.GBSYREGS,.CURDO[DOCREG]);	

	GBSYCT_ONESCOUNT(.GBSYREGS);


	%(***FOR ALL LOOPS THAT END ON THIS LABEL, MUST TELL THE BB ALLOCATOR
		THAT THE REGS USED FOR CALCULATING THE LP INDEX AND THE  LP CT GET
		THEIR PREVIOUS CONTENTS CLOBBERED***)%
	UNTIL .TMP EQL 0	!WALK THRU LINKED LIST OF DO STMNTS THAT TERMINATE ON THIS LABEL
	DO
	BEGIN
		CURDO_.TMP[LEFTP];	!DO STMNT POINTED TO BY THIS ELEM IN LINKED LIST
					! OF DO STMNTS THAT END ON THIS LABEL
		REGCLOBB(.CURDO[DOCREG]);	!REG USED FOR LP CT
		REGCLOBB(.CURDO[DOIREG]);	!REG USED FOR LP IX
		DOVAR_.CURDO[DOSYM];	!VAR USED FOR LP INDEX
		IF .DOVAR[DBLFLG]	!IF LP INDEX IS DP OR COMPLEX
		THEN REGCLOBB(.CURDO[DOIREG]+1);
		TMP_.TMP[RIGHTP];	!GO ON TO NEXT LINK IN LIST
	END;

END;	! of ALCDOEND


GLOBAL ROUTINE STCMRETURN=
BEGIN
	!DETERMINE COMPLEXITY FOR A RETURN EXPRESSION
	MAP BASE CSTMNT:TREEPTR;
	REGISTER BASE NXTSTMN;	!NEXT STMNT AFTER THE RETURN

	%(***KEEP A COUNT OF "RETURN" STMNTS. DO NOT COUNT A RETURN THAT PRECEDES THE END STMNT**)%

	NXTSTMN_.CSTMNT[SRCLINK];
	IF .NXTSTMN EQL 0 THEN RETNCT_.RETNCT+1
	ELSE
	%(**SKIP OVER THE CONTINUE INSERTED BY THE OPTIMIZER AT THE END OF THE PROGRAM**)%
	IF .NXTSTMN[SRCID] EQL CONTID AND .NXTSTMN[OPTCONFLG]
	THEN
	BEGIN
		 NXTSTMN_.NXTSTMN[SRCLINK];	
		IF .NXTSTMN[SRCID] NEQ ENDID THEN RETNCT_.RETNCT+1
	END

	ELSE IF .NXTSTMN[SRCID] NEQ ENDID THEN RETNCT_.RETNCT+1;

	!IF THERE IS NO EXPRESSION COMPLEXITY IS ZERO

	IF .CSTMNT[RETEXPR] EQL 0 THEN
		CSTMNT[SRCCMPLX]_0
	ELSE
	BEGIN
		TREEPTR_.CSTMNT[RETEXPR];
		CSTMNT[SRCCMPLX]_SETCOMPLEXITY();
	END;
	!IF ITS A SIMPLE CONSTANT ALLOCATE IT.
	!THIS WILL CAUSE BAD CODE
	!BUT IS EXPEDIENT
	IF .TREEPTR[OPR1] EQL CONSTFL THEN ALOCONST(.TREEPTR);

END;	! of STCMRETURN


GLOBAL ROUTINE ALCRETURN=
BEGIN
	!
	!REGISTER ALLOCATION FOR A RETURN I
	LOCAL RA;
	MAP PEXPRNODE TREEPTR:CSTMNT;


	IF .CSTMNT[RETEXPR] EQL 0 THEN RETURN;
	TREEPTR_.CSTMNT[RETEXPR];
	IF .TREEPTR[OPRCLS] NEQ DATAOPR THEN
	BEGIN
		RA_FIRSTONE(.STBSYR);
		ALCINREG(.RA,.STBSYR,.STRGCT);
	END;

END;	! of ALCRETURN


ROUTINE HDRTMP=
LSTHDR(4,3,PLIT'?M?JTEMPORARIES?M?J?M?J?0');


GLOBAL ROUTINE ALCAVARS=
BEGIN

%1245%	! Rewritten by TFV on 3-Aug-81

	! Allocate temporaries needed for register save and restore if
	! this is a subprogram function

	MACRO TNAME(INDX)=

		! Macro TNAME defines  .A00NN temp names  to save  the
		! registers used  in the  function, where  "nn"  comes
		! from the macro argument INDX.
	
		(SIXBIT '.A0000' OR
%1505%			(((INDX) AND #70)^3) OR
			(((INDX) AND #7))
		)$;

	LOCAL NEDTOSAV,NAMER,T;
	LABEL FNLOK;
	MAP BASE T;

	REGISTER CNT;

	ROUTINE ALCA(T)=
	BEGIN
		MAP BASE T;
		T[IDADDR] = .LOWLOC;	! Allocate one word for .Annnn variable
		LOWLOC = .LOWLOC + 1;
		IF .FLGREG<LISTING>
		THEN
		BEGIN	! List .Annnn variable

			IF .HDRFLG EQL 0
			THEN
			BEGIN	! Output header

				HDRFLG = 1;
				HDRTMP();

			END;	! Output header

			LISTSYM(.T);	! List .Annnn variable
 
			TCNT = .TCNT + 1;

			IF .TCNT GTR 5
			THEN
			BEGIN	! Output CRLF after 5 items

				TCNT = 0;
				CRLF;
				HEADCHK();

			END;	! Output CRLF after 5 items

		END;	! List .Annnn variable
	END;

	CNT = 0;

	! First find out if it is a subprogram.

	IF .FLGREG<PROGTYP> EQL MAPROG THEN RETURN;

	! It is a subprogram  so generate a temporary  for AC16 if  AC16
	! must be  preserved.   Set  symtype  so  that  all  the  .Annnn
	! variables will be a single word.

	SYMTYPE = REAL;
	NAME = IDTAB;

	IF NOT (.BTTMSTFNFLG AND .IOFIRST EQL 0 AND NOT .LIBARITHFLG)
	THEN
	BEGIN	! AC16 must be preserved

		ENTRY = TNAME(#16);
		T = TBLSEARCH();	! Get symbol table pointer
		ALCA(.T);		! Allocate and list .Annnn variable

	END;	! AC16 must be preserved

	! If multiple entry points then generate a temporary to hold the
	! epilogue address

	IF .FLGREG<MULTENT>
	THEN
	BEGIN
		ENTRY = TNAME(#17);
		T = TBLSEARCH();	! Get symbol table pointer
		ALCA(.T);		! Allocate and list .Annnn variable
	END;

	! If  it  is  a  function  then  generate  temporaries  to  save
	! clobbered registers

FNLOK:
	IF .FLGREG<PROGTYP> EQL FNPROG
	THEN
	BEGIN
		! Determine how many and  which registers must be  saved
		! by examining clobbregs

		NEDTOSAV =LASTONE(.CLOBBREGS);
		IF .NEDTOSAV LSS 0 THEN LEAVE FNLOK;

		DECR I FROM .NEDTOSAV TO 2 DO
		BEGIN
			ENTRY = TNAME(.I);
			T = TBLSEARCH();	! Get symbol table pointer
			ALCA(.T);		! Allocate and list .Annnn var
		END;
	END;

END;	! of ALCAVARS


GLOBAL ROUTINE STCMSFN=
BEGIN

%1455%	! Rewritten by TFV on 5-Jan-82

	! Compute complexity  of  a  statement  function  plus  lots  of
	! subterfuge.  Items of subterfuge include:
	!	1. Substitute a new  variable for each formal.   This is
	!	   done  to   eliminate  confusion   between   statement
	!	   function formals and routine locals of the same name.
	!	2. For  numeric  statement  functions, change  the  slot
	!	   holding the pointer to the expression into a  pointer
	!	   to an assignment statement of the statement  function
	!	   name to the expression.
	!	3. For character  statement functions,  change the  slot
	!	   holding the pointer to the expression into a  pointer
	!	   to a call statement.  It  is either a call to  CHSFN.
	!	   (the subroutine form of CHASN.)  or a call to  CHSFC.
	!	   (the subroutine form of CONCA.).  CHSFC.  is used  if
	!	   the character  expression has  concatenations at  its
	!	   top level,  CHSFN. is  used for  all other  character
	!	   expressions.


%1474%	BIND NOTINCONCAT = FALSE;	! Flag for CMPFNARGS.  It  means
					! that the  first argument  must
					! be processed.

	REGISTER
		NAMER,
		OCSTMNT,
		T;

	LOCAL BASE FNID;	! The identifier name for this function

	OWN BASE COPYARGS;	! Used to determine  if local copies  of
				! the arguments are needed

	MAP
		BASE OCSTMNT,
		ARGUMENTLIST T,
		BASE QQ,	! Convenient temporary
		BASE PREV,	! Convenient temporary
		BASE CSTMNT;

	T = .CSTMNT[SFNLIST];		! Get the argument list
	FNID = .CSTMNT[SFNNAME];	! Get the statement function name

	DECR I FROM .T[ARGCOUNT] TO 1 DO
	BEGIN
		PREV = .T[.I,ARGNPTR];	! Get the argument

		! Add the parameter to the set of variables that can  be
		! left in registers if needed in registers later.

		ADDREGCANDATE(.PREV,.CSTMNT);

		! Init  to  0  the  flag  for  parameter  was   globally
		! allocated (this bit is sometimes left set by phase 1)

		T[.I,ENTGALLOCFLG] = 0;
	END;

	OCSTMNT = .CSTMNT;		! Save pointer to current statement
	CSTMNT = .CSTMNT[SFNEXPR];	! Point cstmnt to assignment  or
					! call node

	IF .FNID[VALTYPE] NEQ CHARACTER
	THEN
	BEGIN	! Numeric statement function

		! Examine the assignment statement of the form SFNNAME =
		! EXPRESSSION. Compute complexity of assignment.

		PREV = .CSTMNT[LHEXP];

		! Insert a regcontents  zero node and  mark the  current
		! statement and the assignment node

		CSTMNT[LHEXP] = MAKRC0(.PREV[VALTYPE]);
		CSTMNT[A1VALFLG] = 1;
		OCSTMNT[VALINR0] = 1;

		STCMASMNT();	! Compute the complexity of the assigment

		COPYARGS = .CSTMNT[RHEXP];	! Pointer to the rhs  of
						! the assignment node

		! We want to  copy the arguments  if there are  function
		! calls under the rhs expression

		COPYARGS = .COPYARGS[FNCALLSFLG];

	END	! Numeric statement function
	ELSE
	BEGIN	! Character statement function

		! Compute the complexity of the argument list

		CSTMNT[SRCCMPLX] = 
			(IF .CSTMNT[CALLIST] EQL 0	
			THEN 0
%1474%			ELSE CMPFNARGS(.CSTMNT[CALLIST],FALSE,NOTINCONCAT));

		STCMCSB();	! Process any common subs

		COPYARGS = 1;	! Make local copies of the arguments

	END;	! Character statement function

	T = .OCSTMNT[SFNLIST];			! Pointer to argument list

	DECR I FROM .T[ARGCOUNT] TO 1 DO
	BEGIN	! Look at each arg

		PREV = .T[.I,ARGNPTR];	! Pointer to this argument

		IF .COPYARGS EQL 1
		THEN			
		BEGIN
			! If local copies of all parameters are  needed,
			! don't bother  for those  never referenced  and
			! hence not allocated.  Also for a formal  array
			! must pick up the pointer.

			IF .PREV[IDATTRIBUT(NOALLOC)]
				AND .PREV[OPERSP] NEQ FORMLARRAY
			THEN	T[.I,ENTNOCOPYFLG] =1;
		END
		ELSE
		BEGIN
%726%			IF .PREV[VALTYPE] NEQ COMPLEX
			THEN
			BEGIN
%726%				! We need to allocate complex  variables
%726%				! because  regular  code  generation  is
%726%				! unprepared   to    cope    with    the
%726%				! complexities  of   picking  up   these
%726%				! special types later on.

				! If   rhs   of   assignment   statement
				! contains  no   function   calls,   the
				! arguments to  this statement  function
				! will  not  need  to  be  copied   into
				! locals.    The   variable   will    be
				! referenced by  @n(16) where  n is  the
				! constant (.I-1).

				PREV[IDATTRIBUT(NOALLOC)] = 1;
				PREV[IDTARGET] = INDBIT + #16^18 + (.I - 1);
				T[.I,ENTNOCOPYFLG] = 1;
			END;
		END;
	END;	! Look at each arg

	CSTMNT = .OCSTMNT;	! Restore the current statement pointer
	CSTMNT[SRCCMPLX] = 0;	! Complexity of statement function

END;	! of STCMSFN

GLOBAL ROUTINE ALCSFN=
BEGIN

%1455%	! Rewritten by TFV on 5-Jan-82

	! Register allocation for a  statement function. SFNEXPR  points
	! to either  an assignment  statement  for a  numeric  statement
	! function or to a call to either CHSFN. or CHSFC.

	REGISTER
		BASE FNID,
		OCSTMNT,
		OCLBRGS;

	MAP BASE CSTMNT;

	! Save the old value  of clobbregs.  This  will be non-zero  and
	! cause errors in the globally optimizing case.  Clobbregs  info
	! for the statement function will be saved in the flags field of
	! the statement function node.

	OCLBRGS = .CLOBBREGS;	! Save clobbregs
	CLOBBREGS = 0;		! Zero clobbregs

	ALCENLIST(.CSTMNT[SFNLIST]);	! Decide which registers to  use
					! to pick up the parameters

	OCSTMNT = .CSTMNT;		! Save pointer to the statement
	FNID = .CSTMNT[SFNNAME];	! Get pointer to the function name

	CSTMNT = .CSTMNT[SFNEXPR];	! Point cstmnt to the expression

	IF .FNID[VALTYPE] NEQ CHARACTER
	THEN	ALCASMNT()		! Numeric - allocate assignment
	ELSE	ALCCALL();		! Character - allocate call

	CSTMNT = .OCSTMNT;		! Restore pointer to the statement
	CSTMNT[SFNCLBREG] = .CLOBBREGS<18,18>;	! Save the clobbregs info
	CLOBBREGS = .OCLBRGS;		! Restore the old clobbregs info

%1274%	! If any temps were needed we must prevent reuse of the .Qnnnn
%1274%	! variables generated. If any are generated we set LASTSFNQ to
%1274%	! the last used (i.e. LASTQ).  We also set QSFNMAX to QMAX.

%1274%	LASTSFNQ = .LASTQ;	! Keep track of last .Qnnnn used
%1274%	QSFNMAX = .QMAX;	! Keep track of size of .Q space

END;	! of ALCSFN

GLOBAL ROUTINE STCMSUB=
BEGIN

	MAP BASE CSTMNT;
	LOCAL ARGUMENTLIST ARGLSTPT;
	OWN BASE ARGUMENT;

	CSTMNT[SRCCMPLX]_0;

	IF .CSTMNT[ENTLIST] NEQ 0 THEN
	BEGIN
	ARGLSTPT_.CSTMNT[ENTLIST];
	INCR I FROM 1 TO .ARGLSTPT[ARGCOUNT] DO
	BEGIN
		%(***INIT TO 0 THE FLAG FOR "THIS VAR WAS GLOBALLY ALLOCATED" (NOTE THAT
			PHASE 1 INITS THIS TO 1 BECAUSE IT WOULD BE THE VALFLG IN AN ARGLIST)***)%
		ARGLSTPT[.I,ENTGALLOCFLG]_0;

		ARGUMENT_.ARGLSTPT[.I,ARGNPTR];
		IF .ARGUMENT NEQ 0 THEN
		BEGIN
			!CHECK THIS FOR NO ALLOCATE BIT IF A
			!SYMBOL THAT IS NOT AN ARRAYNAME.
			!ARRAYNAMES CANNOT BE INCLUDED BECAUSE OF
			!THE DUMMY "ADDRESS" ENTRY CREATED FOR THEM.
			!IT IS NOT THE DUMMY ENTRY THAT IS ON THE
			!LIST BUT IS THE DUMMY ENTRY THAT WILL HAVE THE
			!BIT (NOALLOC) RESET.

			IF .ARGUMENT[OPRCLS] EQL DATAOPR THEN
				IF .ARGUMENT[OPERSP] NEQ FORMLARRAY THEN
					IF .ARGUMENT[IDATTRIBUT(NOALLOC)] THEN
					ARGLSTPT[.I,ENTNOCOPYFLG]_1;

			IF .CSTMNT[ENTNUM] EQL 0	!IF THIS IS THE 1ST ENTRY TO THE SUBROUTINE
			THEN
			ADDREGCANDATE(.ARGUMENT,.CSTMNT);	! THEN THIS PARAM COULD BE LEFT
						! IN A REG FOR USE LATER IN THE 1ST BASIC BLOCK
		END;
	END;
	END;

END;	! of STCMSUB


GLOBAL ROUTINE LPIXSUB=
BEGIN
	!SUBSTITUTE REGCONTENTS NODES IN THE LOOP FOR
	!ALL REFERENCES TO THE INDUCTION VARIBALE.
	!CDONODE POINTS TO THE DO STATEMENT NODE
	!DOWDP ALSO CONTAINS KEY INFO.
	!FIELD DOISUBS = BIT ON MEANS SUBS; BIT OFF MEANS NO SIBS
	!FIELD DOREGPTR = POINTE TO THE REGCONTENTS NODE TO BE SUBSTITUTED

	MAP BASE CSTMNT:CDONODE;
	MAP OBJECTCODE DOWDP;
	OWN BASE ARGNOD;

	!!LOCAL ROUTINE
	ROUTINE DOIO=
	BEGIN
		!LOOK AT I/O LISTS
		LOCAL BASE TMP;

		MISCIO(.CSTMNT);
		TMP_.CSTMNT[IOLIST];
		WHILE .TMP NEQ 0 DO
		BEGIN
			IOSUBSTITUTE(.TMP);
			TMP_.TMP[SRCLINK];
		END;
	END;
	IF .DOWDP EQL 0 THEN RETURN;
	IF .CSTMNT[SRCID] GEQ ENCOID THEN RETURN;


	ITMCT_1;
	GLOBREG[1]_.CDONODE[DOSYM];
	CHOSEN[1]_.DOWDP[DOREGPTR];

	!LOOK AT THE COMMON SUB-EXPRESSIONS TOO
	IF .CSTMNT[SRCCOMNSUB] NEQ 0 THEN
	BEGIN
		ARGNOD_.CSTMNT[SRCCOMNSUB];
		WHILE .ARGNOD NEQ 0 DO
		BEGIN
			LEAFSUBSTITUTE(.ARGNOD);
			ARGNOD_.ARGNOD[SRCLINK];
		END;
	END;

	SELECT .CSTMNT[SRCID] OF NSET

	ASGNID:	!ASSIGNMENT
	BEGIN
		LEAFSUBSTITUTE(.CSTMNT[LHEXP]);
		LEAFSUBSTITUTE(.CSTMNT[RHEXP]);
	END;

	IFAID:	!ARITHMETIC IF
		LEAFSUBSTITUTE(.CSTMNT[AIFEXPR]);

	IFLID:	!	LOGICAL IF
	BEGIN
		LOCAL T1;
		LEAFSUBSTITUTE(.CSTMNT[LIFEXPR]);
		T1_.CSTMNT;
		CSTMNT_.CSTMNT[LIFSTATE];
		LPIXSUB();
		CSTMNT_.T1;
	END;

	READID:		!READ
		DOIO();

	WRITID:	!WRITE
		DOIO();

	FINDID:
		MISCIO(.CSTMNT);

	DECOID:		!DECODE
		DOIO();

	ENCOID:		!ENCODE
		DOIO();

	CGOID:		!COMPUTED GO TO
		LEAFSUBSTITUTE(.CSTMNT[CGOTOLBL]);

	AGOID:		!ASSIGNED GO TO
		LEAFSUBSTITUTE(.CSTMNT[AGOTOLBL]);

	RETUID:		!RETURN
		IF .CSTMNT[RETEXPR] NEQ 0 THEN
			LEAFSUBSTITUTE(.CSTMNT[RETEXPR]);

	STOPID:		!STOP
		IF .CSTMNT[STOPIDENT] NEQ 0 THEN
			LEAFSUBSTITUTE(.CSTMNT[STOPIDENT]);

	!REMEMBER ASSIGN STATEMENTS WITH ARRAY ELEMENTS
	ASSIID:		!ASSIGN STATEMENT
		LEAFSUBSTITUTE(.CSTMNT[ASISYM]);

	TESN;

	IF .CSTMNT[SRCLBL] NEQ 0 THEN
	IF .CSTMNT[SRCLBL] EQL .CDONODE[DOLBL] THEN
	DOWDP_0;

END;	! of LPIXSUB


GLOBAL ROUTINE ALCENTRY=
%(***************************************************************************
	ROUTINE TO PERFORM REGISTER ALLOCATION FOR THE REGS TO BE USED TO
	PICK UP THE VARS ON THE PARAMETER LIST AT AN ENTRY.
	CALLED WITH THE GLOBAL CSTMNT POINTING TO THE STATEMENT NODE FOR
	THE ENTRY STATEMENT
***************************************************************************)%
BEGIN
	MAP BASE CSTMNT;

	IF .CSTMNT[ENTLIST] NEQ 0
	THEN ALCENLIST(.CSTMNT[ENTLIST]);	! If  this   entry   has
						! parameters,  determine
						! which registers to use
						! to pick them up

END;	! of ALCENTRY


GLOBAL ROUTINE ALCENLIST(ARGLST)=
%(***************************************************************************
	ROUTINE TO DETERMINE WHICH REGS TO USE TO PICK UP THE
	THE PARAMS OF A FN,SUBR,OR STMNT FN.
	CALLED WITH THE ARG "ARGLST" POINTING TO THE PARAMETER LIST.
***************************************************************************)%
BEGIN
	OWN OSTBSYR;	!SAVE VAL OF STBSYR

	REGISTER PEXPRNODE ARGN;	!PTR TO THE SYMBOL TABLE ENTRY FOR A GIVEN ARG
	MAP ARGUMENTLIST ARGLST;	!PTR TO THE ARG LIST FOR THIS ENTRY



	%(**ALLOW REGS 0 AND 1 TO BE USED FOR PICKING UP ARGS**)%
	OSTBSYR_.STBSYR;
	STBSYR_.STBSYR OR #600000000000;

	%(***ALLOC A REG TO USE TO PICK UP EACH ARG***)%
	INCR I FROM 1 TO .ARGLST[ARGCOUNT]
	DO
	BEGIN
		ARGN_.ARGLST[.I,ARGNPTR];	!SYM TABLE ENTRY FOR THIS ARG

		IF .ARGLST[.I,ENTGALLOCFLG]	!IF THIS PARAM WAS ALREADY ASSIGNED A REG
					! BY THE GLOBAL ALLOCATOR
			OR .ARGLST[.I,ENTNOCOPYFLG]	! OR IF THIS PARAM WONT BE COPIED INTO A LOCAL
		THEN BEGIN END		! LEAVE THAT ASSIGNMENT ALONE

		ELSE
		BEGIN
			OWN RA;	!REG TO USE FOR PICKING UP THE ARG

			RA_AFREEREG(.STBSYR,TRUE,.ARGN[DBLFLG]);	!GET A FREE REG TO USE
			REGCLOBB(.RA);		!IF RA PREVIOUSLY HAD A VAR IN IT
						! IT WILL NOW BE CLOBBERED
			IF .ARGN[DBLFLG] THEN REGCLOBB(.RA+1);	!IF ARG IS DP, CLOBBER 2 REGS
			ARGLST[.I,ENTAC]_.RA;		!SET FIELD IN ARGLIST ENTRY INDICATING REG
			IF .ARGLST[.I,ENTSAVREGFLG]	!IF IT WILL BE USEFUL IN THE 1ST BASIC BLOCK
					! OF THE ROUTINE TO HAVE THIS PARAM LEFT IN A REG
			THEN
			SAVEREG(.RA,.ARGN,0,.ARGLST[.I,ENTSONNXTUSE]);	!REMEMBER THAT THIS REG CONTAINS
							! THE VAL OF THIS ARG
			CLOBBREGS_SETBIT(.CLOBBREGS,.RA);	!REMEMBER THAT THIS REG GETS CLOBBERED
							! WHEN EXECUTING THIS SUBROUTINE
			IF .ARGN[DBLFLG] THEN CLOBBREGS_SETBIT(.CLOBBREGS,.RA+1);
		END;
	END;
	STBSYR_.OSTBSYR

END;	! of ALCENLIST


GLOBAL ROUTINE ARGSIZREST(ENTSTMNT)=
%(***************************************************************************
	FOR THE ENTRY STMNT POINTED TO BY "ENTSTMNT", DETERMINE THE
	MAXIMUM PRECISION OF ANY ARGUMENTS WHOSE VALUES
	MUST BE COPIED BACK AT SUBROUTINE EXIT.
	THUS IF THERE ARE NO PARAMETERS AT THIS ENTRY WHOSE VALS
	ARE MODIFIED IN THE ROUTINE, RETURN 0. IF ONLY SINGLE PRECISION
	PARAMETERS HAVE THEIR VALS MODIFIED RETURN 1. IF DOULBLE-WORD
	PARAMETERS HAVE THEIR VALS MODIFIED RETURN 2.
	ARGS THAT ARE GLOBALLY ALLOCATED TO REGISTERS AND ARGS THAT DO
	NOT HAVE LOCAL COPIES DONT COUNT.
***************************************************************************)%
BEGIN
	MAP BASE ENTSTMNT;
	REGISTER ARGUMENTLIST ARGLST;
	REGISTER SNGLFOUND;	!FLAG FOR "A SINGLE PREC ARG TO BE RESTORED" WAS FOUND

	IF (ARGLST_.ENTSTMNT[ENTLIST]) EQL 0 THEN RETURN 0;	!IF THERE ARE NO PARAMETERS

	SNGLFOUND_FALSE;

	INCR I FROM 1 TO .ARGLST[ARGCOUNT]	!LOOK AT ALL ARGS ON THE LIST
	DO
	BEGIN
		IF .ARGLST[.I,ENTNOCOPYFLG]	!PARAMS THAT DO NOT HAVE LOCAL COPIES
			OR .ARGLST[.I,ENTGALLOCFLG]	! OR THAT ARE GLOBALLY ALLOCATED
			OR .ARGLST[.I,ARGNPTR] EQL 0	! OR THAT ARE LABELS
		THEN BEGIN END		! SHOULD BE IGNORED
		ELSE
		BEGIN
			REGISTER PEXPRNODE SYMENTRY;
			SYMENTRY_.ARGLST[.I,ARGNPTR];
			IF .SYMENTRY[IDATTRIBUT(STORD)]	!IF PARAM IS STORED INTO
				AND .SYMENTRY[OPERSP] EQL FORMLVAR	! AND IS A VARIABLE (NOT AN ARRAY)
			THEN
			BEGIN
				IF .SYMENTRY[DBLFLG]	!IF PARAM IS DOUBLE-WORD
				THEN RETURN 2
				ELSE
				SNGLFOUND_TRUE;
			END
		END
	END;	!END OF INCR LOOP

	IF .SNGLFOUND THEN RETURN 1 ELSE RETURN 0;

END;	! of ARGSIZREST


GLOBAL ROUTINE FNVALCHK=
%(***************************************************************************
	CHECK WHETHER THE ASSIGNMENT STATEMENT POINTED TO BY THE GLOBAL
	"CSTMNT" ASSIGNS THE VALUE TO BE RETURNED BY THIS FUNCTION
	AND WHETHER THE ASSIGNMENT IS IMMEDIATELY FOLLOWED BY A "RETURN".
	IF SO, AND IF THE FUNCTION IS SINGLE ENTRY AND IF REG 0 WILL
	NOT BE NEEDED FOR STORING BACK VALUES OF PARAMETERS, SUBSTITUTE
	A "REGCONTENTS" OF REG 0 ON THE LHS OF THE ASSIGNMENT STMNT AND
	DONT PICK UP THE FN VAL INTO REG 0 WHEN EXITING THE FUNCTION.
***************************************************************************)%
BEGIN
	MAP BASE CSTMNT;
	REGISTER BASE TSTMNT;
	REGISTER PEXPRNODE LHNODE;

%1163% IF .FLGREG<DBGINDX> THEN RETURN;	!/DEB:INDEX - must update function variable

	IF (.RETNCT+1) NEQ .ASVCT	!IF THERE ARE MORE "RETURN" (PLUS "END") STMNTS IN THIS PROGRAM
				! THAN THERE ARE ASSIGNMENTS OF THE VAL DIRECTLY BEFORE RETURN STMNTS
				! CANNOT DO THIS OPTIM
	THEN RETURN;

	IF NOT ASNFNVAL() THEN RETURN;	!IF THE FN VAL IS NOT ASSIGNED BY THIS STMNT OR THIS STMNT DOES
					! NOT PRECEDE A RETURN

	LHNODE_.CSTMNT[LHEXP];	!PTR TO LHS OF ASSIGNMENT

	TSTMNT_.SORCPTR<LEFT>;	!PTR TO 1ST STMNT IN PROGRAM
	WHILE .TSTMNT[SRCID] NEQ ENTRID	!SKIP DUMMY CONTINUES AT START OF PROGRAM
	DO
	BEGIN
		TSTMNT_.TSTMNT[CLINK];	
		IF .TSTMNT EQL 0 THEN CGERR();	!IF REACH END OF PROGRAM AND HAVENT FOUND THE ENTRY
	END;

	IF ARGSIZREST(.TSTMNT) + (1+.LHNODE[DBLFLG])	!SUM OF NUMBER OF REGS NEEDED FOR
			! RESTORING ARGS IN EPILOGUE AND NUMBER OF REGS NEEDED TO HOLD THE FN VAL
		GTR 2	! IF  NEED MORE THAN 2 REGS ALTOGETHER THEN
			! CANT  LEAVE THE FN VAL IN REGS 0-1 WHILE ARGS
			! ARE RESTORED
	THEN RETURN;

	!RETURN IF THERE ARE MULTIPLE ENTRIES
	IF .FLGREG<MULTENT> THEN RETURN;

	IF .TSTMNT[ENTSYM] NEQ .LHNODE THEN CGERR();	!SYMBOL AT THIS ENTRY BETTER BE THE LHS OF
				! THIS ASSIGNMENT OR WE HAVE AN INTERNAL COMPILER ERROR


	TSTMNT[VALINR0]_1;	!SET FLAG IN ENTRY FOR "VAL OF THIS FN ALREADY IN REG 0, NEEDNT PICK IT UP
	CSTMNT[LHEXP]_MAKRC0(.LHNODE[VALTYPE]);	!SUBSTITUTE A REGCONTENTS 0 ON LHS

	IF NOT .CSTMNT[A2VALFLG]	!IF RHS IS NOT A SIMPLE VAR
	THEN
	BEGIN
		REGISTER PEXPRNODE RHNODE;
		RHNODE_.CSTMNT[RHEXP];	!EXPRESSION ON RHS
		RHNODE[RESRFFLG]_0;	! IF HAD FLAG FOR "REF TO LHS VAR OCCURS IN THIS EXPR, CLEAR IT
	END;

END;	! of FNVALCHK


GLOBAL ROUTINE FNVLCH1=
%(***************************************************************************
	ROUTINE CALLED IN "COMPLEXITY" PASS FOR EACH ASSIGNMENT STMNT.
	CHECKS WHETHER THAT STMNT ASSIGNS THE VAL OF THE FN
	DIRECTLY BEFORE A "RETURN". KEEEPS A COUNT OF ALL
	SUCH ASSIGNMENTS.
***************************************************************************)%
BEGIN
	MAP BASE CSTMNT;
	IF ASNFNVAL() THEN ASVCT_.ASVCT+1;

END;	! of FNVLCH1


GLOBAL ROUTINE ASNFNVAL=
%(***************************************************************************
	ROUTINE TO CHECK WHETHER THE STMNT POINTED TO BY CSTMNT 
	ASSIGNS THE VAL OF THIS FN AND
	ITS EXECUTION  DIRECTLY PRECEDES EXECUTION OF A "RETURN"
	STMNT. CSTMNT IS ASSUMED TO PT TO AN ASSIGNMENT STMNT.
***************************************************************************)%
BEGIN
	MAP BASE CSTMNT;
	REGISTER PEXPRNODE LHNODE;
	REGISTER BASE TSTMNT;
	REGISTER PEXPRNODE LABENT;	!LABEL ENTRY FOR LABEL ON THE RETURN(IF THERE IS ONE)
	LHNODE_.CSTMNT[LHEXP];	!LHS OF ASSIGNMENT STMNT
	IF NOT(.LHNODE[OPRCLS] EQL DATAOPR AND .LHNODE[IDATTRIBUT(FENTRYNAME)])	!IF LHS IS NOT THE FN VAL
	THEN
	RETURN FALSE;

	IF (LABENT_.CSTMNT[SRCLBL]) NEQ 0	!IF THIS STMNT HAS A LABEL
	THEN (IF .LABENT[SNDOLVL] NEQ 0		! IF THAT LABEL ENDS ANY DO LOOPS
		THEN RETURN FALSE);		! THEN THE VAR FOR THE FN VAL MIGHT
					! BE USED AGAIN AFTER EXECUTION OF THIS STMNT


	TSTMNT_.CSTMNT[CLINK];	!STMNT AFTER THE ASSIGNMENT
	IF .TSTMNT EQL 0 THEN RETURN FALSE;	!IF THIS ASSIGNMENT WAS UNDER AN IF
	IF .TSTMNT[SRCID] EQL CONTID AND .TSTMNT[OPTCONFLG]	!SKIP THE DUMMY CONTINUE INSERTED BY THE OPTIMIZER
	THEN TSTMNT_.TSTMNT[CLINK];
	IF NOT(.TSTMNT[SRCID] EQL RETUID OR .TSTMNT[SRCID] EQL ENDID)	!IF NEXT STMNT IS NOT RETURN OR END
	THEN RETURN FALSE;

	IF (LABENT_.TSTMNT[SRCLBL]) NEQ 0	!IF THE RETURN HAS A LABEL
	THEN (IF .LABENT[SNREFNO] GTR 1 THEN RETURN FALSE);	! IF THAT LABEL IS REFERENCED, RETURN FALSE

	RETURN TRUE;	!OTHERWISE, DO HAVE THE FN VAL ASSIGNED JUST BEFORE A RETURN
END;	! of ASNFNVAL

END
ELUDOM