Google
 

Trailing-Edge - PDP-10 Archives - fortv11 - alcblo.bli
There are 12 other files named alcblo.bli in the archive. Click here to see a list.
!COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1973, 1987
!ALL RIGHTS RESERVED.
!
!THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
!ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH LICENSE AND WITH THE
!INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR ANY  OTHER
!COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
!OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF THE  SOFTWARE  IS  HEREBY
!TRANSFERRED.
!
!THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT  NOTICE
!AND  SHOULD  NOT  BE  CONSTRUED  AS A COMMITMENT BY DIGITAL EQUIPMENT
!CORPORATION.
!
!DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY  OF  ITS
!SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.

!AUTHOR: S. MURPHY/SRM/JNG/TFV/TJK

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

GLOBAL BIND ALCBLV = #11^24 + 0^18 + #2407;	! Version Date: 21-Jun-84

%(

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

55	-----	-----	MUST END A BASIC BLOCK ON AN IF THAT CONTAINS A CALL
56	-----	-----	WHEN INSERT AN ENTRY IN REGSTATE TABLE
			MUST CLEAR VARINREGFLG OF A POSSIBLE ENTRY
			BEING WRITTEN OVER. THIS CAN HAPPEN FOR:
				A=B
				C=B
			WHERE B IS GLOBALLY ALLOCATED TO A REG
57	-----	-----	MUST CHECK FOR A BASIC BLOCK
		TERMINATED BY THE NEXT STMNT HAVING A LABEL BEFORE
			CHECK FOR IT TERMINATED BY THE PREVIOUS STMNT
		A DO STMNT (SINCE IN THAT CASE WE STILL REMEMBER THE
		LP INDEX
58	632	24245	IN REGCLOBB, DON'T CLEAR VARINREGFLG FOR THE
			VARIABLE IN THE REGISTER IF THE VARIABLE IS
			ALSO IN ANOTHER REGISTER. THIS CAN HAPPEN IF
			A VAR IS LIVING IN 0, MOVED TO 2 FOR INDEXING,
			THEN 0 IS REGLOBB'ED BY A FUNCTION CALL., (JNG)
59	652	NONE	EDIT 632 NEEDS TO CARE ABOUT DOUBLE WORD VARS, (DCE)

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

60	1024	SRM	21-Nov-80	NONE
	Fixed REGCLOBB to work for REAL='literal' when
	compiling /gfloating. REGCLOBB had assumed that
	if a literal was in an AC the 2nd half must be
	in an adjacent AC. This was always true because
	we did a "type conversion" on the literal and
	created a constant of type REAL that contained
	the bits from the literal. When compiling
	/gfloating we dont do this "conversion".

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

61	1212	TFV	29-Apr-81	------
	Replace LITERAL with HOLLERITH.


62	1226	SRM	19-June-81
	Change REGCONTAINING to look at ACs starting from 15
	rather than starting from 0. That way, if have the value
	in both AC 0 and another AC will get the non-0 AC.
	This makes better code for the case:
		SUBROUTINE S(I)
		A(I)=0
		B(I)=0

63	1231	CKS	23-Jun-81
	Remove edit 62.  It has slight side effect that a double word
	quantity in N and N+1 is "found" in (N+1,N+2) instead of (N,N+1).

***** End V7 Development *****

2006	TJK	6-Oct-83
	Add call to ENDSMZTRIP in ALCBLOCK to determine if the current
	statement (pointed to by CSTMNT)  should end a basic block  by
	virtue of ending at least one DO-loop with the MAYBEZTRIP flag
	set.


***** Begin Version 10 *****

2214	TJK	26-Sep-83
	Fix ALCBLOCK to correctly undo an AOBJN loop control word.  It
	now calls UNFLDO.

2227	TJK	21-Oct-83
	Rewrite ALCBLOCK to have it call ENDSBBLOCK to determine where
	a basic  block  ends.   Also added  external  declaration  for
	ENDSBBLOCK, removed external  declaration for ENDSMZTRIP  (now
	called only by ENDSBBLOCK), and fixed some comments.

2407	TJK	21-Jun-84
	Have VARCLOBB check for SUBSTRING nodes.

***** End V10 Development *****

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

)%

	SWITCHES NOLIST;

	REQUIRE FIRST.BLI;
	REQUIRE TABLES.BLI;

	SWITCHES LIST;

FORWARD
	ALCBLOCK(0),
	AFREEREG(3),
	REGCONTAINING(1),
	VARCLOBB(1),
	CLOBBCOMEQV,
	CLOBBEQV,
	REGCLOBB(1),
	CLRRGSTATE,
	INIRGSTATE,
	SAVEREG(4),
	FREEPAIRS(1);

EXTERNAL
	ALCSTMN,	! ROUTINE TO PERFORM LOCAL REGISTER ALLOCATION
			! FOR A GIVEN STATEMENT
	BLOCKBSYREGS,	! SPECIFIES REGISTERS WHOSE CONTENTS WILL BE NEEDED LATER
			! IN THIS BASIC BLOCK. The values SHOULD BE PRESERVED
			! BIT PATTERN INDICATING WHICH REGS ARE IN USE
			! BY THE BASIC BLOCK ALLOCATOR
			! THIS WORD CONTAINS A BIT PATTERN IN WHICH ONES REPRESENT
			! REGISTERS THAT ARE FREE, ZEROES REPRESENT REGISTERS WHOSE
			! CONTENTS WILL BE NEEDED LATER IN THIS BASIC BLOCK
	CGERR,		! ROUTINE TO GIVE MESSAGE WHEN INTERNAL COMPILER ERROR
			! IS DETECTED
	CLOBBREGS,	! GLOBAL IN WHICH THE BIT CORRESPONDING TO
			! EACH REG CLOBBERED BY A GIVEN SUBPROGRAM
			! IS SET (USED TO DETERMINE WHICH REGS TO SAVE/RESTORE)
	BASE CSTMNT,	! POINTER TO CURRENT STATEMENT BEING PROCESSED
%2227%	ENDSBBLOCK,	! Checks if the current statement (pointed to
			! by CSTMNT) ends a basic block
	GBSYCT,		! NUMBER OF FREE REGS IN GBSYREGS
	GBSYREGS,	! BIT PATTERN REPRESENTING THE REGS LEFT FREE BY THE
			! GLOBAL ALLOCATOR (A ONE REPRESENTS A FREE REG, A ZERO A BUSY ONE)
	ISN,		! INTERNAL SEQ NUMBER OF THE STMNT BEING PROCESSED
			! (THIS IS USED FOR ERROR MESSAGES)
%1274%	LASTQ,		! Pointer to the last .Q used by the current statement
%1274%	LASTSFNQ,	! Pointer to the last .Q used by statement
			! functions
			! The .Q variables between QANCHOR and LASTSFNQ can not
			! be reused by other statements
	NOBBREGSLOAD,	! FLAG INDICATING THE BB ALLOCATOR CANNOT ASSUME
			! THAT THE CODE FOR THE EXPRESSION CURRENTLY BEING
			! PROCESSED WILL ALWAYS BE EXECUTED AND
			! HENCE THAT WE CANNOT ASSUME THAT REGS LOADED
			! IN PROCESSING THIS EXPR HAVE THE VALS INDICATED
			! (E.G. THIS FLAG IS SET WHEN PROCESSING A LOG IF)
	OLDGBSYREGS,	! BIT PATTERN SET UP BY THE GLOBAL OPTIMIZER TO
			! INDICATE REGS AVAILABLE OUTSIDE THE CURRENT DO LOOP
			! WHEN THE CURRENT LOOP WAS GLOBALLY ALLOCATED
%2227%	QLOC,		! Next location in .Q space to be used by the
			! current statement
%1274%	QSFNMAX,	! Maximum size of .Q space used by statement functions
	STBSYR,		! BIT PATTERN REPRESENTING THE REGS AVAILABLE FOR
			! USE WITHIN A GIVEN STMNT
	STRGCT,		! NUMBER OF FREE REGS IN STBSYR
%2214%	UNFLDO;		! ROUTINE TO UNDO AN AOBJN LOOP CONTROL WORD

BIND RGSENTSIZE=2;	!NUMBER OF WDS IN EACH ENTRY OF THE REGSTATE TABLE

OWN
	BLKISN,		!SEQ NUMBER WITHIN THIS BLOCK OF THE STMNT CURRENTLY BEING PROCESSED
	RGSTBL REGSTATE[RGSENTSIZE*16];	!THIS TABLE HAS AN ENTRY FOR EACH OF THE 16 ACS 
			! EACH ENTRY INDICATES WHICH VARS/CONSTS ARE IN EACH REG

GLOBAL ROUTINE ALCBLOCK =	![2227] Routine rewritten in this edit

!++
! FUNCTIONAL DESCRIPTION:
!
!	This is the top level routine for the second pass of the basic
!	block register allocator.  It causes local register allocation
!	to be performed for every statement in a basic block.
!
!	This routine  is  called with  CSTMNT  pointing to  the  first
!	statement of a basic block.   It returns with CSTMNT  pointing
!	to the first statement of the next basic block.  If the end of
!	the program has been reached  it returns with CSTMNT equal  to
!	zero.  The REGSTATE table is cleared when it has completed the
!	pass over a basic block.
!
!	If the basic block is terminated by a DO statement, and if the
!	following conditions hold:
!
!		1.  The only reason for terminating the basic block is
!		    because of the DO statement
!
!		2.  The DO  statement  has the  flags  NEDSMATRLZ  and
!		    SAVREGFLG both set
!
!		3.  The DO-variable is a single-word data type  (i.e.,
!		    it doesn't have the DBLFLG flag set)
!
!	then a REGSTATE table entry for the DO-variable is created  so
!	that the register  containing the DO-variable  can be used  in
!	the next basic block.   In addition, if the  loop is in  AOBJN
!	form it will be converted to non-AOBJN form.
!
!	The REGSTATE  table should  be  properly initialized  for  the
!	first  call  to  this  routine.   For  subsequent  calls,  the
!	REGSTATE table should be  in the state  in which this  routine
!	left it after processing the preceding basic block.
!
! FORMAL PARAMETERS:
!
!	NONE
!
! IMPLICIT INPUTS:
!
!	CSTMNT		points to  the first  statement of  the  basic
!			block to be processed.
!
!	GBSYCT		is the number of  free registers indicated  by
!			GBSYREGS.
!
!	GBSYREGS	is the bit pattern representing the  registers
!			left free by the global allocator.
!
!	LASTSFNQ	points to the  last .Qnnnn  temporary used  by
!			the STATEMENT FUNCTION statements.
!
!	QSFNMAX		is the maximum  size of the  .Q space used  by
!			the STATEMENT FUNCTION statements.
!
! IMPLICIT OUTPUTS:
!
!	BLKISN	is the  basic block  internal sequence  number of  the
!		current statement.
!
!	CSTMNT	points to the  next statement to  be processed.   Upon
!		return from this routine,  CSTMNT points to the  first
!		statement of  the next  basic  block to  be  processed
!		(unless we just processed the last basic block of  the
!		current program unit, in which case CSTMNT is zero).
!
!	ISN	is the internal sequence number of the statement being
!		processed (used for error messages).
!
!	LASTQ	points to  the  last  .Qnnnn  temporary  used  by  the
!		current statement.
!
!	QLOC	is the next location (offset)  in .Q space to be  used
!		by the current statement.
!
!	STBSYR	is the bit pattern of  registers available for use  by
!		the statement being processed.
!
!	STRGCT	is the number of free registers indicated by STBSYR.
!
! ROUTINE VALUE:
!
!	NONE
!
! SIDE EFFECTS:
!
!	NONE
!
!--


BEGIN
	LABEL BLOCK;		! Used to leave basic block processing loop
	REGISTER ENDVAL;	! Used to save value returned by ENDSBBLOCK

	BLKISN = 1;	! First statement in basic block has block ISN of 1

	! Now perform register allocation  for each statement in  this
	! basic block.

BLOCK:	WHILE TRUE
	DO
	BEGIN	! For each statement in basic block

		ISN = .CSTMNT[SRCISN];	! ISN for the current statement

		STBSYR = .GBSYREGS;	! Set of regs available for use
					! in this statement

		STRGCT = .GBSYCT;	! Number of free regs indicated
					! by STBSYR

%1274%		LASTQ = .LASTSFNQ;	! Init pointer to last .Qnnnn used
					! by statement functions.  These are 
					! not reused by other statements

%1274%		QLOC = .QSFNMAX;	! Set location to allocate next .Qnnnn
					! var to after the SFN .Q variables

		ALCSTMN();	! Do local reg allocation for current stmnt

		! Check if the current statement is the last statement
		! of the basic block  by calling ENDSBBLOCK, and  save
		! the return value in ENDVAL.  If it's 0, we  continue
		! the basic block.  Otherwise  we end the basic  block
		! by leaving BLOCK; ENDVAL will be 1 for a normal  end
		! of the basic  block, and  2 if the  basic block  was
		! ended for the sole reason that CSTMNT points to a DO
		! statement.

		IF (ENDVAL = ENDSBBLOCK()) NEQ 0	! End of basic block?
		THEN LEAVE BLOCK;			! Yes, leave the loop

		! The current statement (pointed  to by CSTMNT)  isn't
		! the last statement of the basic block.

		CSTMNT = .CSTMNT[SRCLINK];	! Move to next statement
		BLKISN = .BLKISN+1;		! Bump basic block ISN

	END;	! For each statement in basic block

	! We're at the end of the basic block.  The last statement  of
	! the basic block has had register allocation performed on it,
	! and is pointed to by CSTMNT.  Also, ENDVAL is either 1 or 2;
	! 1 for a normal end  of the basic block,  and 2 if the  basic
	! block was ended for the sole reason that CSTMNT points to  a
	! DO statement.

	CLRRGSTATE();	! Clear the REGSTATE table (i.e. can no longer
			! assume any previous values in registers)

	! Check for special DO case

	IF .ENDVAL EQL 2		! Did BB end because of a DO?
	THEN IF .CSTMNT[NEDSMATRLZ]	! And is the DO-variable materialized?
	THEN IF .CSTMNT[SAVREGFLG]	! And should the DO-var stay in a reg?
	THEN
	BEGIN	! Special DO case

		REGISTER PEXPRNODE DOVAR;	! DOVAR points to the symbol
		DOVAR = .CSTMNT[DOSYM];		! node for the DO-variable

		! If the DO-variable is single-word, set up a REGSTATE
		! entry, and un-AOBJN it if FLCWD is set.

		IF NOT .DOVAR[DBLFLG]	! If the DO-variable is single-word
		THEN
		BEGIN	! Single-word DO-variable

			! Set up a REGSTATE entry for the register
			! containing the DO-variable.

			SAVEREG(.CSTMNT[DOIREG],.DOVAR,0,
				.CSTMNT[SRCSONNXTUSE]);

			! If the loop  is in  AOBJN form,  undo it  so
			! that the initial  value for the  DO-variable
			! will be picked up in a register by itself.

			IF .CSTMNT[FLCWD]	! Is the loop in AOBJN form?
			THEN
			BEGIN	! Loop is AOBJN

%2214%				UNFLDO(.CSTMNT);	! Un-AOBJN the loop
				CSTMNT[INITLIMMED] = 1;

				! Choose a free register for the control word

				CSTMNT[DOCREG] = AFREEREG(CLRBIT(.STBSYR,
					.CSTMNT[DOIREG]),FALSE,FALSE);

			END;	! Loop is AOBJN

		END;	! Single-word DO-variable

	END;	! Special DO case

	CSTMNT = .CSTMNT[SRCLINK];	! Have CSTMNT point to the next stmnt
					! (i.e., the first stmnt of the next
					! basic block)

END;	! of ALCBLOCK

ROUTINE PAIRREGS(BSYRG1)=
	%(**********
		GIVEN A BIT PATTERN "BSYRG1" IN WHICH ZEROES REPRESENT REGISTERS THAT ARE
		BUSY AND ONES REPRESENT REGISTERS THAT ARE FREE, THIS ROUTINE RETURNS
		A BIT PATTERN IN WHICH ZEROES REPRESENT REGISTERS FOR WHICH THE OTHER
		HALF OF THEIR EVEN-ODD PAIR IS BUSY AND ONES REPRESENT REGISTERS
		FOR WHICH THE OTHER HALF OF THEIR EVEN-ODD PAIR IS FREE.

		FOR BOTTOMMOST FUNCTIONS, BIT 0 OF EACH BIT PATTERN REPRESENTS REGISTER 2
		BIT 1 REPRESENTS REGISTER 3, ETC. FOR NON-BOTTOMMOST FUNCTIONS, BIT
		0 REPRESENTS REGISTER 15, BIT 1 REGISTER 14, ETC.

		HENCE FOR BOTH NON-BOTTOMMOST FUNCTIONS AND BOTTOMMOST FUNCTIONS,
		THE BIT PAIRS 0-1, 2-3, 4-5, ETC CORRESPOND TO THE REGISTER
		PAIRS 2-3 (OR 14-15), 4-5 (OR 12-13), ETC
	**********)%
BEGIN
		((.BSYRG1 AND #525252525252)^(-1)) !THE ODD REGS CORRESP TO FREE EVEN REGS;
	OR
		((.BSYRG1 AND #252525252525)^1) !THE EVEN REGS CORRESPTO FREE ODD REGS;
END;	! PAIRREGS

GLOBAL ROUTINE AFREEREG (BSYREGS,BLKFLG,DOUBLFLG)=
%(**********
	ROUTINE TO RETURN A REGISTER (OR REGISTER PAIR) TO BE USED FOR A GIVEN COMPUTATION.
	THE PARAMETERS FOR THIS ROUTINE ARE:
		1.  BSYREGS-SPECIFIES REGISTERS THAT IT IS POSSIBLE TO USE.  THAT IS, REGISTERS THAT
		    ARE NOT EITHER:
			A.  HOLDING INTERMEDIATE RESULTS IN THIS STATEMENT
			B.  ALLOCATED BY THE GLOBAL REGISTER ALLOCATOR
		    THE BITS IN BSYREGS EACH REPRESENT A REGISTER.  IF A BIT IS ZERO THE CORRESPONDING
		    REGISTER IS NOT AVAILABLE. 
		2.  BLKFLG-IF THIS FLAG IS "TRUE," THE REGISTER TO BE RETURNED WILL BE USED TO
		    HOLD A VALUE THAT WILL BE PRESERVED OVER SUCCEEDING STATEMENTS IN THIS BASIC BLOCK
		3.  DOUBLFLG-SPECIFIES WHETHER A SINGLE REGISTER OR A REGISTER PAIR IS REQUIRED

	THIS ROUTINE USES THE GLOBAL "BLOCKBSYREGS" WHICH SPECIFIES REGISTERS THAT WE PREFER TO
	NOT USE BECAUSE THEIR CONTENTS WILL BE NEEDED LATER IN THIS BASIC BLOCK.  THE
	FORMAT OF "BLOCKBSYREGS" IS SIMILAR TO THAT OF "BSYREGS" (I.E. IF A BIT IS ZERO, THE
	CORRESPONDING REGISTER SHOULD PREFERABLY NOT BE USED).

	WHEN ALL REGISTERS ARE BUSY AND HENCE SOME REGISTER FROM "BLOCKBSYREGS" MUST
	BE USED, WE SELECT THE REGISTER WHOSE NEXT USE IS THE FURTHEST IN THE
	FUTURE.  THE "REGSTATE" TABLE CONTAINS THE INTERNAL SEQUENCE NUMBER
	OF THE NEXT USE OF EACH REGISTER THAT BLOCKBSYREGS INDICATES SHOULD BE PRESERVED.
**********)%
BEGIN
	REGISTER BESTREGS;			!REGISTERS THAT ARE AVAILABLE ACCORDING TO "BSYREGS" AND
						!NOT OF FUTURE USE IN THIS BASIC BLOCK
	OWN RGTOUSE;	!REGISTER WHOSE NEXT USE IS FURTHEST IN THE FUTURE



	%(***DETERMINE WHICH REGISTERS ARE FREE**)%
	BESTREGS_(IF .DOUBLFLG			!FOR DOUBLE-PRECISION, MUST
			THEN (.BSYREGS AND DPBSYREGS(.BLOCKBSYREGS)) !CONVERT BLOCKBSYREGS TO DP MODE
			ELSE (.BSYREGS AND .BLOCKBSYREGS));

	IF .BESTREGS NEQ 0
	THEN
	%(****IF THERE ARE SOME FREE REGISTERS****)%
	BEGIN
		IF .DOUBLFLG			!IF ARE CONSIDERING REGISTER PAIRS ALREADY,
		THEN RETURN FIRSTONE(.BESTREGS) !SIMPLY RETURN THE FIRST AVAILABLE PAIR
		ELSE
		%(***IF A SINGLE REGISTER IS BEING USED, TRY TO USE SINGLE REGISTERS WHOSE
			ADJACENT REGISTERS ARE ALREADY IN USE***)%
		BEGIN
			REGISTER VERYBESTREGS;

			IF .BLKFLG		!IF THIS REGISTER IS TO BE PRESERVED ACROSS SOME FUTURE
			THEN			!STATEMENTS
			BEGIN
				VERYBESTREGS_.BESTREGS AND !IF THERE ARE ANY FREE REGISTERS FOR WHICH THE
					NOT PAIRREGS(.BLOCKBSYREGS); !OTHER HALF OF THEIR EVEN-ODD PAIR IS ALREADY
				IF .VERYBESTREGS NEQ 0 !HOLDING A VALUE FOR FUTURE STATEMENTS, USE ONE OF THEM
				THEN
				BESTREGS_.VERYBESTREGS
			END;

			VERYBESTREGS_.BESTREGS AND !IF THERE ARE ANY FREE REGISTERS FOR WHICH THE OTHER
				NOT PAIRREGS(.BSYREGS); !HALF OF THEIR EVEN-ODD PAIR IS ALREADY HOLDING
			IF .VERYBESTREGS NEQ 0	!A VALUE ACROSS THIS STATEMENT, USE ONE OF THEM
			THEN
			BESTREGS_.VERYBESTREGS;

			RETURN FIRSTONE(.BESTREGS)
		END
	END

	ELSE

	%(***IF THERE ARE NO FREE REGISTERS, THEN MUST USE ONE OF THE REGISTERS THAT HOLDS A
		VALUE OF FUTURE USE (I.E. A REGISTER IN BLOCKBSYREGS).  PICK THE REGISTERS WHOSE
		NEXT USE IS FURTHEST AWAY
	****)%
	BEGIN
		REGISTER MAXNXUSE;
		IF .DOUBLFLG
		THEN
		%(***IF NEED TO GET A REGISTER PAIR***)%
		BEGIN
			REGISTER NXPAIRUSE;	!THE ISN OF THE NEXT STATEMENT AT WHICH EITHER REG IN A PAIR IS USED
			%(***WALK THRU THE REGISTER-STATE TABLE TO FIND THE REGISTER PAIR WHOSE NEXT USE
				IS THE FURTHEST AWAY***)%
			MAXNXUSE_0;
			INCR REG FROM #2 TO #14 BY 2
			DO
			BEGIN
				IF .REGSTATE[.REG,RGNXUSE] LSS .BLKISN	!IF THE "NEXT USE" OF THIS
					AND .REGSTATE[.REG+1,RGNXUSE] LSS .BLKISN	! REG HAS ALREADY
								! BEEN PASSED
					AND BITSET(.BSYREGS,.REG)	!THEN IF THIS REG IS
							!LEGAL TO USE, USE IT
				THEN RETURN .REG;

				NXPAIRUSE_(IF .REGSTATE[.REG,RGNXUSE] EQL 0 !IF THE EVEN REGISTER HAS NO FUTURE USE, THEN
					THEN .REGSTATE[.REG+1,RGNXUSE]  !THE NEXT USE IS THE NEXT USE FOR THE ODD REG
					ELSE IF .REGSTATE[.REG+1,RGNXUSE]EQL 0 !IF THE ODD REGISTER HAS NO FUTURE USE,
					THEN .REGSTATE[.REG,RGNXUSE] !THE NEXT USE IS THE NEXT USE FOR THE EVEN REG
					ELSE IF .REGSTATE[.REG,RGNXUSE] !IF THE NEXT USE OF THE EVEN REGISTER IS
						LEQ .REGSTATE[.REG+1,RGNXUSE] !SOONER THAN THE NEXT USE OF THE ODD REGISTER
					THEN .REGSTATE[.REG,RGNXUSE] !THE NEXT USE FOR THE PAIR IS THE NEXT USE FOR THE EVEN REG
					ELSE .REGSTATE[.REG+1,RGNXUSE]); !OTHERWISE, IT'S THE NEXT USE FOR THE ODD REG

				IF .NXPAIRUSE GTR .MAXNXUSE !IF THE NEXT USE OF THIS PAIR IS
				THEN		!FURTHER AWAY THAN THE BEST PAIR FOUND
				BEGIN		!SO FAR,
					IF BITSET(.BSYREGS,.REG) !AND THIS PAIR IS A LEGAL ONE TO USE
					THEN
					BEGIN
						MAXNXUSE_.NXPAIRUSE; !THEN USE THIS PAIR
						RGTOUSE_.REG
					END;
				END
			END			!END OF WALK THRU REGSTATE TABLE FOR PAIRS

		END				!END OF BLOCK TO FIND A REGISTER PAIR

		ELSE
		%(***IF NEED A SINGLE REGISTER***)%
		BEGIN
			%(***WALK THRU THE REGISTER STATE TABLE TO FIND THE REGISTER WHOSE NEXT USE
				IS FURTHEST AWAY***)%
			MAXNXUSE_0;
			INCR REG FROM #2 TO #15 BY 1
			DO
			BEGIN
				IF .REGSTATE[.REG,RGNXUSE] LSS .BLKISN	!IF THE "NEXT USE" OF THIS
						! REG HAS ALREADY BEEN PASSED
					AND BITSET(.BSYREGS,.REG)	!THEN IF THIS REG IS LEGAL TO USE
				THEN RETURN .REG;	!THEN USE THIS REG

				IF .REGSTATE[.REG,RGNXUSE] !IF THE NEXT USE OF THIS REG
					GTR .MAXNXUSE	 !IS GREATER THAN THE MAXIMUN FOUND FOR
				THEN			!ANY REG
				BEGIN
					IF BITSET(.BSYREGS,.REG) !AND THIS REG IS A LEGAL ONE TO USE
					THEN
					BEGIN
						MAXNXUSE_.REGSTATE[.REG,RGNXUSE]; !USE THIS REG
						RGTOUSE_.REG
					END
				END
			END
		END;				!END OF BLOCK TO FIND A SINGLE REG

		IF .MAXNXUSE EQL 0 THEN CGERR(); !IF CAN'T FIND A REG TO USE THAT'S CURRENTLY
						!HOLDING A BASIC BLOCK VARIABLE
		RETURN .RGTOUSE
	END
END;	! AFREEREG

GLOBAL ROUTINE REGCONTAINING(SYMPTR)=
%(**********
	THIS ROUTINE DETERMINES WHETHER THE VALUE OF THE VARIABLE/CONSTANT INDICATED
	BY "SYMPTR" IS ALREADY IN SOME REGISTER.  IF SO, IT RETURNS THE REGISTER,
	IF NOT, IT RETURNS MINUS ONE.
	"SYMPTR" POINTS TO THE SYMBOL TABLE OR CONSTANT TABLE ENTRY FOR THE VARIABLE/CONSTANT
**********)%
BEGIN
	MAP PEXPRNODE SYMPTR;

	IF .SYMPTR[OPRCLS] NEQ DATAOPR		!IF ARE NOT LOOKING AT A VARIABLE OR CONSTANT
	THEN RETURN -1;

	IF NOT .SYMPTR[VARINREGFLG]		!FLAG IN SYMBOL/CONSTENT TABLE ENTRIES INDICATING
	THEN RETURN -1;				!THAT VALUE IS IN A REGISTER

%[1231]% INCR REG FROM 0 TO #15			!IF VALUE IS IN A REGISTER, SEARCH THE REGISTER
	DO					!STATE TABLE TO DETERMINE WHICH REGISTER-FOR
	BEGIN					!AN EVEN-ODD PAIR WILL FIND THE EVEN REG FIRST
		IF .REGSTATE[.REG,RGVAR1] EQL .SYMPTR !IF EITHER OF THE TWO POSSIBLE VARIABLES WHOSE
		THEN RETURN .REG;		!VALUES ARE IN THIS REG ARE IDENTICAL
		IF .REGSTATE[.REG,RGVAR2] EQL .SYMPTR !TO SYMPTR, THEN THIS
		THEN RETURN .REG;		!IS THE ENTRY DESIRED
	END;

	CGERR();				!IF THE "VARINREGFLG" WAS SET IN THE SYMBOL TABLE ENTRY, BUT
						!THE VARIABLE COULDN'T BE FOUND IN THE REGSTATE TABLE, HAVE A
						!COMPILER ERROR
END;	! REGCONTAINING

GLOBAL ROUTINE VARCLOBB(SYMPTR)=
%(**********
	THIS ROUTINE IS CALLED WHEN THE VALUE OF A VARIABLE IS MODIFIED.
	IF SOME REGISTER HAS BEEN ASSUMED TO CONTAIN THE VALUE OF THAT VARIABLE,
	THEN THAT ASSUMPTION CAN NO LONGER BE MADE.
	IF THE VARIABLE IS EQUIVALENCED THEN ALL VARIABLES THAT ARE EQUIVALENCED OR IN
	COMMON MUST BE ASSUMED TO BE CLOBBERED
**********)%
BEGIN
	MAP PEXPRNODE SYMPTR;

%2407%	! Make sure  we  handle  SUBSTRING.   This  is  important  for
%2407%	! common/equivalence.
%2407%
%2407%	IF .SYMPTR[OPRCLS] EQL SUBSTRING
%2407%	THEN SYMPTR = .SYMPTR[ARG4PTR];		! Get full string

	IF .SYMPTR[OPRCLS] EQL ARRAYREF	!IF AN ARRAY ELEMENT IS BEING CLOBBERED
	THEN
	BEGIN
		REGISTER PEXPRNODE ARRAYNM;	!PTR TO SYM TAB ENTRY FOR THE ARRAY NAME
		ARRAYNM_.SYMPTR[ARG1PTR];

		IF .ARRAYNM[IDATTRIBUT(INEQV)]	!IF THE ARRAY IS IN AN EQUIVALENCE STMNT
		THEN CLOBBCOMEQV()		!MUST ASSUME THAT ALL VARS IN EQUIVALENCE OR
						! IN COMMON ARE CLOBBERED

		ELSE IF .ARRAYNM[IDATTRIBUT(INCOM)]	!IF THE VAR IS IN COMMON
		THEN CLOBBEQV()			! MUST ASSUME THAT ALL VARS IN EQUIVALENCE STMNTS
						! ARE CLOBBERED
	END

	ELSE
	IF .SYMPTR[OPRCLS] EQL DATAOPR	!IF ITS A SIMPLE VAR THAT'S BEING CLOBBERED
		AND .SYMPTR[OPR1] NEQ CONSTFL
	THEN
	BEGIN
	


		IF .SYMPTR[IDATTRIBUT(INEQV)]		!IF THIS VAN IS EQUIVALENCED
		THEN CLOBBCOMEQV()			!ASSUME THAT ALL VARS IN EQUIVALENCE OR COMMON
							!STMNTS HAVE BEEN CLOBBERED
		ELSE
		IF .SYMPTR[VARINREGFLG]		!IF SOME REG IS ASSUMED TO CONTAIN THE VAL OF
		THEN					!THIS VARIABLE
		BEGIN
			SYMPTR[VARINREGFLG]_0;	!CAN NO LONGER ASSUME THAT THIS VAR IS IN A REG

			%(***SEARCH THE REGSTATE TABLE FOR THE ENTRY FOR THIS VARIABLE AND CLEAR THAT ENTRY**)%
			INCR REG FROM 0 TO #15
			DO
			BEGIN
				IF .REGSTATE[.REG,RGVAR1] EQL .SYMPTR !IF THIS IS THE REG THAT CONTAINED "SYMPTR"
				THEN			!CLEAR ITS ENTRY IN THE REGSTATE TABLE
				BEGIN
					REGSTATE[.REG,RGVAR1]_0;
					IF .REGSTATE[.REG,RGVAR2] EQL 0 !IF "SYMPTR" WAS THE ONLY VARIABLE
					THEN		!IN THIS REG, THEN RETURN THIS
					BEGIN		!REG TO THE SET OF FREE REGISTERS
						REGSTATE[.REG,RGNXUSE]_0;
						BLOCKBSYREGS_SETBIT(.BLOCKBSYREGS,.REG)
					END;

				END;

				IF .REGSTATE[.REG,RGVAR2] EQL .SYMPTR !IF THIS IS THE REG THAT CONTAINED "SYMPTR"
				THEN			!CLEAR ITS ENTRY
				BEGIN
					REGSTATE[.REG,RGVAR2]_0;
					IF .REGSTATE[.REG,RGVAR1] EQL 0 !IF "SYMPTR" WAS THE ONLY VARIABLE
					THEN		!IN THIS REG, THEN RETURN THIS
					BEGIN		!REG TO THE SET OF FREE REGISTERS
						REGSTATE[.REG,RGNXUSE]_0;
						BLOCKBSYREGS_SETBIT(.BLOCKBSYREGS,.REG)
					END;
				END;

			END;				!END OF INCR LOOP
		END;	!END OF BLOCK FOR SYMPTR KNOWN TO BE IN A REG

		IF .SYMPTR[IDATTRIBUT(INCOM)]	!IF SYMPTR IS IN COMMON
		THEN CLOBBEQV();		! MUST ASSUME THAT ALL VARS IN EQUIVALENCE STMNTS
						! ARE CLOBBERED

	END	!END OF BLOCK FOR "SYMPTR" A SIMPLE VARIABLE
END;	! VARCLOBB

ROUTINE COMOREQV(SYMENTRY)=
	%(**********
		LOCAL ROUTINE TO TEST WHETHER "SYMENTRY" POINTS TO A SYMBOL
		TABLE ENTRY FOR A VARIABLE THAT OCCURS IN A COMMON OR
		EQUIVALENCE STATEMENT
	**********)%
BEGIN
	MAP BASE SYMENTRY;
	IF .SYMENTRY[OPR1] EQL CONSTFL	!IF SYMENTRY IS NOT A SYMBOL TABLE ENTRY
	THEN FALSE			!(I.E. IS A CONSTANT TABLE ENTRY)

	ELSE
	(.SYMENTRY[IDATTRIBUT(INEQV)]	!FLAG FOR "VARIABLE IS IN AN EQUIVALENCE STMNT"
		OR
		.SYMENTRY[IDATTRIBUT(INCOM)] !FLAG FOR "VARIABLE IS IN A COMMON STMNT"
	)
END;	! COMOREQV

GLOBAL ROUTINE CLOBBCOMEQV=
%(**********
	ROUTINE TO ASSUME THAT ALL VARIABLES IN COMMON AND ALL VARIABLES
	THAT ARE EQUIVALENCED TO ANYTHING HAVE HAD THEIR VALUES MODIFIED.
	REMOVES FROM THE REGSTATE TABLE ALL VARIABLES WHICH ARE IN COMMON OR HAVE
	BEEN EQUIVALENCED
**********)%
BEGIN
	REGISTER PEXPRNODE SYMENTRY;	!POINTER TO SYMBOL/CONSTANT TABLE ENTRY FOR
						!THE VARIABLE IN A GIVEN REGISTER



	INCR REG FROM 0 TO #15			!LOOK AT THE REGSTATE TABLE ENTRY FOR EACH REG
	DO
	BEGIN
		IF (SYMENTRY_.REGSTATE[.REG,RGVAR1]) NEQ 0 !ONE OF THE VARIABLES IN THIS REGISTER
		THEN
		BEGIN
			IF COMOREQV(.SYMENTRY)		!IF VARIABLE IS IN COMMON OR IS EQUIVALENCED
			THEN
			BEGIN
				SYMENTRY[VARINREGFLG]_0;
				REGSTATE[.REG,RGVAR1]_0; !CLEAR ENTRY INDICATING THAT CONTAINS VAL OF THIS VAR
				IF .REGSTATE[.REG,RGVAR2] EQL 0 !IF THIS REG NO LONGER CONTAINS ANY VARIABLES,
				THEN		!RETURN IT TO THE SET OF AVAILABLE REGS
				BEGIN
					REGSTATE[.REG,RGNXUSE]_0;
					BLOCKBSYREGS_SETBIT(.BLOCKBSYREGS,.REG)
				END
			END
		END;

		IF (SYMENTRY_.REGSTATE[.REG,RGVAR2]) NEQ 0 !POSSIBLY A SECOND VARIABLE WHOSE VALUE IS
		THEN				!IN "REG" (E.G. FOR A=B, FOTH A AND B
		BEGIN				!ARE IN THE SAME REG)
			IF COMOREQV(.SYMENTRY)		!IF VARIABLE IS IN COMMON OR IS EQUIVALENCED
			THEN
			BEGIN
				SYMENTRY[VARINREGFLG]_0;
				REGSTATE[.REG,RGVAR2]_0; !CLEAR ENTRY INDICATING THAT "REG" CONTAINS VAL OF THIS VARIABLE
				IF .REGSTATE[.REG,RGVAR1] EQL 0 !IF THIS REG NO LONGER CONTAINS ANY VARIABLES
				THEN		!RETURN IT TO THE SET OF AVAILABLE REGS
				BEGIN
					REGSTATE[.REG,RGNXUSE]_0;
					BLOCKBSYREGS_SETBIT(.BLOCKBSYREGS,.REG)
				END
			END
		END
	END
END;	! CLOBBCOMEQV

GLOBAL ROUTINE CLOBBEQV=
%(***************************************************************************
	ROUTINE TO ASSUME THAT ALL VARS IN EQUIVALENCE STMNTS ARE CLOBBERED.
	REMOVES FROM THE REGSTATE TABLE ALL VARS THAT ARE IN EQUIVALENCE STMNTS;
***************************************************************************)%
BEGIN
	REGISTER PEXPRNODE SYMENTRY;	!PTR TO SYMBOL/CONST TABLE ENTRY FOR THE
					! VAR IN A GIVEN REG

	INCR REG FROM 0 TO #15	!LOOK AT THE ENTRY FOR EACH REG
	DO
	BEGIN
		IF (SYMENTRY_.REGSTATE[.REG,RGVAR1]) NEQ 0	!ONE OF THE VARS IN THIS REG
		THEN
		BEGIN
			IF .SYMENTRY[OPR1] NEQ CONSTFL
				AND .SYMENTRY[IDATTRIBUT(INEQV)]	!IF THIS VAR IS IN AN EQUIVALENCE
			THEN
			(SYMENTRY[VARINREGFLG]_0; REGSTATE[.REG,RGVAR1]_0);	!CAN NO LONGER ASSUME THAT ITS VAL
										! IS IN REG
		END;

		IF (SYMENTRY_.REGSTATE[.REG,RGVAR2]) NEQ 0	!A 2ND VAR IN THIS REG
		THEN
		BEGIN
			IF .SYMENTRY[OPR1] NEQ CONSTFL
				AND .SYMENTRY[IDATTRIBUT(INEQV)]	!IF THIS VAR IS IN EQUIVALENCE
			THEN
			(SYMENTRY[VARINREGFLG]_0; REGSTATE[.REG,RGVAR2]_0);	!REMOVE ITS VAL FROM REG
		END;


		IF .REGSTATE[.REG,RGVAR1] EQL 0 AND .REGSTATE[.REG,RGVAR2] EQL 0	!IF THIS REG NOW
										! CONTAINS NO KNOWN VALS
		THEN
		(REGSTATE[.REG,RGNXUSE]_0; BLOCKBSYREGS_SETBIT(.BLOCKBSYREGS,.REG));	!RETURN IT TO SET
										! OF FREE REGISTERS
	END	!END OF INCR LOOP
END;	! CLOBBEQV

ROUTINE CLRVAR1FIELD(RG)=
	%(**********
		ROUTINE TO CLEAR THE "RGVAR1" FIELD OF A REGSTATE TABLE
		ENTRY AND IF THE "RGVAR2" FIELD IS ALSO 0, TO RETURN THE
		REGISTER TO THE SET OF FREE REGS
	***********)%
BEGIN
		REGSTATE[.RG,RGVAR1]_0;
		IF .REGSTATE[.RG,RGVAR2] EQL 0	!IF THERE IS NOT ANOTHER VAR IN THIS REG
		THEN
		BEGIN
			REGSTATE[.RG,RGNXUSE]_0;	!"LOC OF NEXT USE"
			BLOCKBSYREGS_	!RETURN "RG" TO SET OF FREE REGS
				SETBIT(.BLOCKBSYREGS,.RG)
		END
END;	! CLRVAR1FIELD

ROUTINE CLRVAR2FIELD(RG)=
	%(**********
		ROUTINE TO CLEAR THE "RGVAR2" FIELD OF A REGSTATE TABLE
		ENTRY AND IF THE "RGVAR1" FIELD IS ALSO 0, TO RETURN THE
		REGISTER TO THE SET OF FREE REGS
	***********)%
	BEGIN
		REGSTATE[.RG,RGVAR2]_0;
		IF .REGSTATE[.RG,RGVAR1] EQL 0	!IF THERE IS NOT ANOTHER VAR IN THIS REG
		THEN
		BEGIN
			REGSTATE[.RG,RGNXUSE]_0;	!"LOC OF NEXT USE"
			BLOCKBSYREGS_	!RETURN "RG" TO SET OF FREE REGS
				SETBIT(.BLOCKBSYREGS,.RG)
		END
END;	! CLRVAR2FIELD

ROUTINE CHKOTHREGS(SYMPTR,RG)=
%[632]%	%(***********
[632]		ROUTINE TO CLEAR THE VARINREGFLG FOR SYMPTR IFF SYMPTR IS
[632]		ONLY IN REGISTER RG. THIS KEEPS VARINREGFLG SET IF
[632]		SOME REG CONTAINING SYMPTR IS CLOBBERED, BUT SYMPTR IS
[632]		STILL IN OTHER REG(S).
[632]	************)%
%[632]%	BEGIN
%[632]%
%[632]%		MAP PEXPRNODE SYMPTR;	!THE VAR IN REGISTER RG
%[632]%
%[632]%		REGISTER REGX;		!INDEX FOR LOOP BELOW
%[632]%
%[632]%		SYMPTR[VARINREGFLG]_0;	!ASSUME NOT IN ANY OTHER REG
%[632]%
%[632]%		REGX_0;
%[632]%		WHILE (.REGX LEQ #15) AND NOT .SYMPTR[VARINREGFLG]
%[632]%		DO
%[632]%		BEGIN
%[632]%			IF .REGX NEQ .RG
%[632]%			THEN
%[632]%				IF    .REGSTATE[.REGX,RGVAR1] EQL .SYMPTR
%[632]%				   OR .REGSTATE[.REGX,RGVAR2] EQL .SYMPTR
![652] MUST BE CAREFUL IF THE VARIABLE WAS DOUBLE WORD IN WHICH
![652] CASE WE NEED TO FIND A REG FAR AWAY (MORE THAN 1)
%[652]%				THEN IF NOT .SYMPTR[DBLFLG] THEN SYMPTR[VARINREGFLG]_1
%[652]%					ELSE IF (.REGX+1 NEQ .RG) AND (.REGX-1 NEQ .RG)
%[652]%					THEN SYMPTR[VARINREGFLG]_1;
%[632]%			REGX_.REGX+1
%[632]%		END
%[632]%	END;	! CHKOTHREGS

GLOBAL ROUTINE REGCLOBB(REG)=
%(**********
	THIS ROUTINE IS CALLED WHENEVER THE CONTENTS OF A REGISTER ARE CLOBBERED.
	THIS ROUTINE CLEARS THE REGSTATE TABLE ENTRY FOR THE REGISTER "REG".
	IF ANY VARIABLES HAVE BEEN ASSUMED TO BE IN REG IT CLEARS THE "VARINREGFLG"
	FOR THOSE VARIABLES
	IT ALSO SETS THE BIT CORRESPONDING TO THE REGISTER CLOBBERED
	IN THE GLOBAL "CLOBBREGS" WHICH IS USED TO DETERMINE WHICH REGS
	TO SAVE AND RESTORE IN A FUNCTION
**********)%
BEGIN
	REGISTER PEXPRNODE SYMPTR;		!POINTER TO SYMBOL TABLE OR CONSTANT TABLE ENTRY FOR
						!VARIABLE/CONSTANT WHOSE VALUE IS IN REG




	IF .REG GEQ 2	!UNLESS THE REG IS 0 OR 1 (WHICH ARE NEVER SAVE/RESTORED ACROSS A FN)
	THEN		! SET THE BIT CORRESPONDING TO THAT REG IN THE GLOBAL USED TO KEEP
	CLOBBREGS_	! TRACK OF ALL REGS THAT MUST BE SAVE/RESTORED
		SETBIT(.CLOBBREGS,.REG);



	IF (SYMPTR_.REGSTATE[.REG,RGVAR1]) NEQ 0 !IF SOME VARIABLE IS ASSUMED TO
	THEN					!BE IN "REG"
	BEGIN
%[632]%		CHKOTHREGS(.SYMPTR,.REG);		!CLEAR VARINREGFLG IF NECESSARY
		IF .SYMPTR[DBLFLG]	!IF THE VAR IS DP OR COMPLEX
		THEN	!MUST CLEAR THE ENTRY FOR THE OTHER HALF OF THE VAR
		BEGIN	!WHICH IS IN A REG ADJACENT TO "REG"
			IF .REGSTATE[.REG+1,RGVAR1] EQL .SYMPTR	!IF "REG" WAS THE 1ST HALF
			THEN CLRVAR1FIELD(.REG+1)	!CLEAR ENTRY IN NEXT REG
			ELSE
			IF .REGSTATE[.REG-1,RGVAR1] EQL .SYMPTR	!IF "REG" WAS THE 2ND HALF
			THEN CLRVAR1FIELD(.REG-1)	!CLEAR ENTRY IN PREVIOUS REG
			ELSE	!(IF "RGVAR1" FIELD WAS USED FOR A GIVEN VAR
				! IN ONE REG, CAN ASSUME THAT "RGVAR1" FIELD WILL
				! ALSO BE USED FOR THE OTHER HALF OF THE VAR)
			CGERR()	!IF CANT FIND ENTRY FOR THE OTHER HALF OF THE VAR
		END
	END;
	IF (SYMPTR_.REGSTATE[.REG,RGVAR2]) NEQ 0 !IF SOME SECOND VARIABLE IS ASSUMED
	THEN					!TO BE IN "REG" (E.G. IF HAD "A=B")
	BEGIN
%[632]%		CHKOTHREGS(.SYMPTR,.REG);		!CLEAR VARINREGFLG IF NEEDED
		IF .SYMPTR[DBLFLG]	!IF THE VAR IS DP OR COMPLEX
		THEN	!MUST CLEAR THE ENTRY FOR THE OTHER HALF OF THE VAR
		BEGIN	!WHICH IS IN A REG ADJACENT TO "REG"
			IF .REGSTATE[.REG+1,RGVAR2] EQL .SYMPTR	!IF "REG" WAS THE 1ST HALF
			THEN CLRVAR2FIELD(.REG+1)	!CLEAR ENTRY IN NEXT REG
			ELSE
			IF .REGSTATE[.REG-1,RGVAR2] EQL .SYMPTR	!IF "REG" WAS THE 2ND HALF
			THEN CLRVAR2FIELD(.REG-1)	!CLEAR ENTRY IN PREVIOUS REG
			ELSE	!(IF "RGVAR2" FIELD WAS USED FOR A GIVEN VAR
				! IN ONE REG, CAN ASSUME THAT "RGVAR2" FIELD WILL
				! ALSO BE USED FOR THE OTHER HALF OF THE VAR)

!**;[1212], REGCLOBB, TFV, 29-Apr-81
!**;[1212], Replace LITERAL with HOLLERITH

%[1212]%			IF .SYMPTR[VALTYPE] NEQ HOLLERITH	! IF THE "VAR" IS
%[1024]%						! A LITERAL THAT WAS ASSIGNED TO
%[1024]%						! A REAL, ONLY THE 1ST WORD WILL
%[1024]%						! BE IN AN AC
%[1024]%			THEN			!OTHERWISE, WE SHOULD HAVE FOUND
						! AC THAT CONTAINED THE OTHER WORD
			CGERR()	!IF CANT FIND ENTRY FOR THE OTHER HALF OF THE VAR
		END
	END;

	BLOCKBSYREGS_				!RETURN "REG" TO THE SET
		SETBIT(.BLOCKBSYREGS,.REG);	!OF FREE REGISTERS

	REGSTATE[.REG,RGVAR1]_0;		!CLEAR REGSTATE TABLE
	REGSTATE[.REG,RGVAR2]_0;		!ENTRY FOR REG
	REGSTATE[.REG,RGNXUSE]_0;
END;	! REGCLOBB

GLOBAL ROUTINE CLRRGSTATE=
%(**********
	THIS ROUTINE CLEARS THE REGSTATE TABLE. IT IS CALLED AT THE END OF REGISTER ALLOCATION
	FOR A BASIC BLOCK (WHEN ALL ASSUMPTIONS ABOUT THE CONTENTS OF REGISTERS
	MUST BE DISCARDED)
**********)%
BEGIN

	REGISTER PEXPRNODE SYMPTR;		!POINTER TO SYMBOL/CONSTANT TABLE ENTRY FOR A VARIABLE/CONSTANT
						!WHICH IS ASSUMED TO HAVE BEEN LEFT IN SOME REGISTER

	DECR REG FROM #15 TO 0			!WALK THRU THE REGSTATE TABLE
	DO
	BEGIN
		IF (SYMPTR_.REGSTATE[.REG,RGVAR1]) NEQ 0 !A VARIABLE WHOSE VALUE IS ASSUMED TO BE IN "REG"
		THEN
		BEGIN
			SYMPTR[VARINREGFLG]_0;	!CAN NO LONGER ASSUME THAT THAT VAR IS IN A REG
			REGSTATE[.REG,RGVAR1]_0;
		END;

		IF (SYMPTR_.REGSTATE[.REG,RGVAR2]) NEQ 0 !A SECOND VARIABLE WHOSE VALUE IS ASSUMED TO BE IN "REG"
		THEN
		BEGIN
			SYMPTR[VARINREGFLG]_0;	!CAN NO LONGER ASSUME THAT THAT VAR IS IN A REG
			REGSTATE[.REG,RGVAR2]_0;
		END;

		REGSTATE[.REG,RGNXUSE]_0;	!ISN OF NEXT USE OF THES REG SET TO 0 (MEANING
	END;	!END OF DECR LOOP		!NO FUTURE USE)

	BLOCKBSYREGS_-1;			!ALL REGS ARE NOW AVAILABLE
END;	! CLRRGSTATE

GLOBAL ROUTINE INIRGSTATE=
%(**********
	THIS ROUTINE INITS THE REGISTER STATE TABLE BY ZEROING ALL
	ENTRIES.
*********)%
BEGIN

	DECR REG FROM #15 TO 0	!CLEAR THE ENTRY FOR EACH REG
	DO
	BEGIN
		REGSTATE[.REG,RGVAR1]_0;	!CLEAR ALL FIELDS OF THE ENTRY
		REGSTATE[.REG,RGVAR2]_0;
		REGSTATE[.REG,RGNXUSE]_0;	
	END;

	BLOCKBSYREGS_-1;	!THIS WORD WILL HAVE THE BIT CORRESPONDING TO EACH
				! BUSY REG SET TO 0. INIT IT TO HAVE
				! NO BITS SET TO 0
END;	! INIRGSTATE

GLOBAL ROUTINE SAVEREG(REG,SYMENT1,SYMENT2,USEISN)=
%(**********
	THIS ROUTINE IS CALLED WHEN IT IS DETERMINED THAT THE REGISTER "REG"
	SHOULD BE PRESERVED OVER FUTURE STATEMENTS IN THE CURRENT BASIC BLOCK.
	SYMENT1 IS A POINTER TO THE SYMBOL/CONSTANT TABLE ENTRY FOR THE VARIABLE/CONSTANT
	WHOSE VALUE IS IN REG.  SYMENT2 IS A POINTER TO A POSSIBLE SECOND SYMBOL/CONSTANT
	TABLE ENTRY.  USEISN IS  THE ISN OF THE NEXT USE OF THE VALUE IN REG.
********)%
BEGIN
	MAP PEXPRNODE SYMENT1;
	MAP PEXPRNODE SYMENT2;

	IF .NOBBREGSLOAD	!IF CANNOT ASSUME THAT THE CODE FOR THIS EXPR WILL
	THEN			! ALWAYS BE EXECUTED, THEN CANNOT KEEP THIS VAL IN THIS REG
	RETURN;

	IF .SYMENT2 EQL 0	!IF ARE ONLY TRYING TO REMEMBER 1 VAR
		AND (.REGSTATE[.REG,RGVAR1] EQL .SYMENT1	! AND WE ALREADY KNEW THAT THIS
			OR .REGSTATE[.REG,RGVAR2] EQL .SYMENT1)	! VAR WAS IN THIS REG
	THEN
	BEGIN
		REGSTATE[.REG,RGNXUSE]_.USEISN;	!UPDATE VAL FOR "NEXT USE"
		IF .SYMENT1[DBLFLG]		!IF ARE SAVING  A REG  PAIR
		THEN REGSTATE[.REG+1,RGNXUSE]_.USEISN;	!UPDATE "NXT USE"FOR 2ND HALF
	END
	ELSE
	BEGIN
		REGCLOBB(.REG);		!IF THIS ENTRY ALREADY CONTAINED
				! VARS FORGET ABOUT THEM
		REGSTATE[.REG,RGVAR1]_.SYMENT1;		!SET UP THE REGSTATE TABLE ENTRY FOR THIS REG
		REGSTATE[.REG,RGVAR2]_.SYMENT2;
		REGSTATE[.REG,RGNXUSE]_.USEISN;

		IF .SYMENT1[DBLFLG]			!IF THE VALUE TO BE PRESERVED IS DOUBLE PREC OR COMPLEX
		THEN
		BEGIN
			REGSTATE[.REG+1,RGVAR1]_.SYMENT1; !SET UP REGSTATE TABLE ENTRY FOR THE REG FOLLOWING THIS REG
			REGSTATE[.REG+1,RGVAR2]_.SYMENT2;
			REGSTATE[.REG+1,RGNXUSE]_.USEISN;
		END;
	END;

	BLOCKBSYREGS_CLRBIT(.BLOCKBSYREGS,.REG); !TURN OFF BIT IN BLOCKBSYREGS CORRESPONDING
						!TO THIS REG TO INDICATE IT SHOULD
						!BE PRESERVED
	IF  .SYMENT1[DBLFLG]	!IF ARE SAVING A REG PAIR

	THEN
		BLOCKBSYREGS_CLRBIT(.BLOCKBSYREGS,.REG+1); !CLEAR BIT IN BLOCKBSYREGS TO INDICATE
						!THAT REG AFTER "REG" MUST BE
						!PRESERVED

	SYMENT1[VARINREGFLG]_1;			!SET FLAG IN SYMBOL/CONST TABLE ENTRY INDICATING THAT THIS
						!VAR IS IN SOME REG
	IF .SYMENT2 NEQ 0			!IF A SECOND VARIABLE IS ALSO IN THIS REG (EG FOR A=B)
	THEN
	SYMENT2[VARINREGFLG]_1;			!SET FLAG IN ITS SYMBOL TABLE ENTRY AS WELL
END;	! SAVEREG

GLOBAL ROUTINE FREEPAIRS(BSYREGS)=
%(***************************************************************************
	GIVEN A BIT PATTERN "BSYREGS" IN WHICH 0'S INDICATE BUSY REGS AND
	1'S INDICATE FREE REGS, THIS ROUTINE RETURNS THE NUMBER
	OF EVEN-ODD REG PAIRS THAT ARE FREE
***************************************************************************)%
BEGIN
	RETURN ONESCOUNT(
		(.BSYREGS AND #525252525252)^(-1)	!BITS FOR FREE EVEN REGISTERS
						! SHIFTED RIGHT TO INDICATE ODD REG FOLLOWING EACH
		AND
		(.BSYREGS AND #252525252525)	!BITS FOR FREE ODD REGISTERS
		)
END;	! FREEPAIRS

END
ELUDOM