Google
 

Trailing-Edge - PDP-10 Archives - FORTRAN-10_Alpha_31-jul-86 - skstmn.bli
There are 12 other files named skstmn.bli in the archive. Click here to see a list.
!COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1972, 1986
!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 & NORMA ABEL/HPW/MD/TFV/CKS/CDM/TJK/AHM/MEM

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

GLOBAL BIND SKSTV = #11^24 + 0^18 + #4527;	! Version Date:	1-Jan-86

%(

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

83	-----	-----	INTERFACE TO SKOPTIO
84	-----	-----	INCLUDE E1LISTCALL AND E2LISTCALL NODES
			IN IODEPNDS
85	-----	-----	PERFORM P2SKEL ON RECORD NUMBERS
			ALSO, REMOVE A=A
86	-----	-----	FIX 85 TO CHECK FOR NEG/NOT FLAGS TOO
87	-----	-----	IF DO LOOP INDEX IS IN COMMON MAKE SURE
			AT LEAST MATRLZIXONLY IS SET
88	-----	-----	FIX FOR NEW SFN HANDLING

89	-----	-----	IF DBGINDX FLAG IS SET, MATERIALIZE LOOP
			INDEX (EDIT TO "DOENSKL")
90	-----	-----	P2REGCNTS SHOULD NOT CALL ITSELF FOR
			THE SUBSTATEMENT OF A LOGICAL IF
91	-----	-----	WHEN AN ARITH IF IS TRANSFORMED INTO LOG
			IF/GOTO, MUST CALL P2SKSTMN FOR THE GOTO INSERTED
			UNDER THE LOGICAL IF (SO THAT "P2REGCNTS"
			WILL GET CALLED FOR IT AND THE LABEL WILL BE EXAMINED
			FOR A TRANSFER OUT OF THE CURRENT LOOP)
92	242	15010	DO NOT DELETE THE CONDITIONAL IN A LOGICAL
			IF WHEN THE SUBSTATEMENT IS A CONTINUE.
93	260	-----	ADD A DOT TO CORRECTLY MATERILIZE DO LOOP INDEXES
			WHICH ARE IN COMMON

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

94	761	TFV	1-Mar-80	-----
	Add KTYPCG for /GFLOATING type conversions

95	1026	DCE	24-Nov-80	-----
	Fix FILTER to call itself rather than LOOKELEM2 for IOLSTCALL

96	1050	EGM	5-Feb-81	--------
	Retain arithmetic if expression if it contains function references,
	otherwise, if all three labels are the same, reduce the label reference
	count by 2 at the same time as replacing the IF by a GO TO.

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

1167	TFV	11-Jan-83	20-18247
	Fix LOOKELEM2 to  check E1/E2LISTCALLs  to see if  the count  or
	increment depend  upon previous  iolist elements.

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

97	1207	DCE	3-Apr-81	-----
	Handle all the I/O list dependencies introduced by FORTRAN-77.
	In particular, be wary of final loop values and dependencies
	introduced by them.  Changes to LOOKELEM2, IODEPENDS, and
	addition of new routine - LPVARDEPNDS.

98	1441	SRM	16-Dec-81
	Fix FORMIOL to not fold:
		X, F(X)
	since F(X) might have side effects on X.
	Formerly we were erroneously disallowing:
		F(X), X
	which can be folded with no problem.

99	1455	TFV	5-Jan-82	------
	Modify SKSFN  for character  statement functions.   The  SFNEXPR
	field of a  numeric statement function  points to an  assignment
	node.  The SFNEXPR field for character statement function points
	to a call node.  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
	concatenation at its  top level,  CHSFN. is used  for all  other
	character expressions.

1527	CKS	29-Apr-82
	Add SKOPNCLS to do skeleton walk for expressions under OPEN and
	CLOSE statements.

1530	TFV	4-May-82
	Setup TOPIO  in  P2SKSTMNT.  It  points to  the  top  level  I/O
	statement above  an  IOLSCLS  node.   It  is  used  to  set  the
	IOLSTATEMENT field.  Also  use symbols for  the size of  IOLSCLS
	nodes in FORMIOLST.

1626	CKS	31-Aug-82
	Call P2 optimizations on ENCODE/DECODE string length.

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

1742	TFV	13-Apr-83
	Fix I/O  deficiencies.  Do  skeleton walk  for all  I/O  keyword
	values.  Modify SKIOLST and SKIO  so P2SKSTMNT can use them  for
	FIND, REWIND, etc..  Fix checks  for DONOAOBJN on inner do  loop
	index as keyword value.  Have P2REGCNTS check all I/O statements
	for transfers out of the loop.

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

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

2200	TFV	23-Mar-83
	Do skeleton  optimizations for  the INQUIRE  statement.   Modify
	SKOPNCLS to do the work.

2243	CDM	13-Dec-83
	Detect AOBJN DO loop register indexes into large arrays  (arrays
	in .LARG.).  This is  done in the  skeleton optimizer, and  will
	disable the  DO loop  from using  an AOBJN  instruction for  the
	cases that can be caught  this early in compilation.  This  will
	prevent the negative left half  of the AOBJN register  appearing
	to be an  invalid section  number when indexing  into the  array
	when running in a non-zero section.

2272	TJK	20-Jan-84
	Have SKCALL call P2SKFOLD  if the CALL  statement is really  a
	character assignment or character  statement function so  that
	subconcatenations are  now folded  in these  cases.  Also  fix
	SKCALL to  set AVALFLG  when  an expression  is reduced  to  a
	DATAOPR due to skeleton optimizations.

2302	TJK	2-Feb-84
	Add new flag IDCLOBB to the IDFNATTRIB field of a symbol table
	entry.  This flag is set for certain library routines  (called
	as subroutines).  It indicates that  ACs are not preserved  by
	the call.

	Have CHASGN generate calls to  CASNM.  instead of CHASN.   for
	single-source character  assignments,  and CNCAM.  instead  of
	CONCA. for character concatenation assignments.  Also have  it
	set IDCLOBB for these routines, which don't preserve ACs.

	Replace a check for CONCA. with a check for CNCAM. in  SKCALL.

	Have ALCCALL mark registers 2-15 (octal) as being clobbered if
	IDCLOBB is set.

2304	TJK	8-Feb-84
	Add  P2SKOVRLP  to  do   compile-time  overlap  checking   for
	character assignments.  Have SKCALL  call this routine if  the
	CALL statement is really a character assignment.

2365	TJK	6-Jun-84
	Move checks for inner DO-variable  in SKIO and SKOPNCLS  until
	after SKWALK, in case folding occurs.

2405	TJK	21-Jun-84
	Correct a  problem with  edit 1441.   It missed  the place  in
	FOLDIOLST where  CONTFN  must be  called.   Delete  DEFONCIOL,
	whose references may be replaced by direct calls to  IODEPNDS.
	Improve FILTER (in LOOKELEM2).

2463	AHM	8-Oct-84
	Disabuse ARNOAOBJN of the notion that ARRAYREFs for large numeric
	arrays with large offsets won't use the offset in an EFIW.

***** End V10 Development *****
***** End Revision History *****
***** Begin Version 11 *****

4500	MEM	22-Jan-85
	Modified SKOPNCLS to perform skeleton optimizations on IOKEY
	expressions in OPEN statements.

4501	MEM	22-Jan-85
	Modified SKIO to perform skeleton optimizations on the IOKEY
	expression.

4502	MEM	22-Jan-85
	Modify P2SKSTMNT and LOKIOUT to handle the DELETE statement.

4503	MEM	22-Jan-85
	Modify P2SKSTMNT and LOKIOUT to handle the REWRITE statement.

4504	MEM	22-Jan-85
	Modify P2SKSTMNT and LOKIOUT to handle the UNLOCK statement.

4517	MEM	4-Oct-85
	Modified SKCALL to check if the first arg is 1-char (by calling
	SINGLECHARCHK) and we are calling a character assignment routine.
	If we are then convert the call stmt into an assignment and put
	a CHAR node over the left side of the asmnt and put an ICHAR node
	over the right side. Set the INCRFLG in the CHAR and ICHAR nodes.
	If there are arrayrefs or substrings under the CHAR or ICHAR nodes
	then increment their offsets.

4522	MEM	5-Nov-85
	Modified SKCALL to create an assignment node for 1-char
	assignments with incremented and/or unincremented bytepointers.

4527	CDM	1-Jan-86
	VMS Long symbols phase II.  Convert all internal symbols from
	one word of Sixbit to [length,,pointer].  The lengths will be one
	(word) until a later edit, which will store and use long symbols.

ENDV11
)%

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

! Below is for use in making PLM's with RUNOFF
!++
!.LITERAL
!--

OWN CTR;

%(***KEEP A TABLE OF THE LABELS INSIDE AN INNERMOST LOOP AND KEEP A COUNT OF REFERENCES 
	TO EACH LABEL THAT OCCUR WITHIN THE LOOP****)%
STRUCTURE LPLABLST[CT,POS,SIZE]=	!DEFINE THE STRUCTURE OF THAT TABLE
	( (.LPLABLST+.CT)<.POS,.SIZE> );
MACRO LABL=LEFT$,	!PTR TO THE STMNT NUMBER TABLE ENTRY FOR THE LABEL
	LOCREFCT=RIGHT$;	!CT OF REFS THAT OCCUR INSIDE THIS LOOP

OWN TRANSFOUT;	!THIS FLAG IS SET TO "TRUE" IF THE INNER DO LOOP
			! BEING PROCESSED HAS TRANSFERS OUT

FORWARD
	P2SKSTMNT,
	SKASMNT,
	SKSFN,
	SKRETURN,
	SKAGO,
	SKCGO,
	DELGOLABS(1),
	SKLOGIF,
	SKARIF,
	SKASSI,
	SKIO(1),
	SKDECENC(1),
	SKOPNCLS,
	SKCALL,
	FOLDIOLST,
	FORMIOLST(1),
	LOOKELEM2(2),
	IODEPNDS(2),
	LPVARDEPNDS(2),
	DOP2SKL,
	TRINTOLOOP,
	DOENSKL,
	P2REGCNTS,
	LOOKOUT(1),
	LOKIOUT,
%2243%	ARNOAOBJN(1);	! Routine to decide if array reference's address
%2243%			! calc should make a innermost DO loop not AOBJN.

EXTERNAL
	C1H,
	C1L,
	C2H,
	C2L,
	BASE CDONODE,	! Ptr to the previous DO statement in this program
	CGERR,
	LPLABLST CHOSEN,	! Used to hold table of labels inside a loop
	BASE CIOCALL,	! Ptr to current IOLISTCALL node being built
	BASE CIOCLAST,	! Ptr to last element on IOLISTCALL node being built
	CNSTCMB,
	CONTFN,
	CONTVAR,
	COPRIX,
	CORMAN,
	BASE CSTMNT,	! pointer to current statement
	DNEGCNST,
	OBJECTCODE DOWDP,
	FOLDAIF,
	FOLDLIF,
	INNERLOOP,	! Flag set while processing stmnts in an innermost loop
	INPFLAG,	! Flag set for statements that do input
	KBOOLBASE,
	KTYPCB,
%761%	KTYPCG,		! For /GFLOATING type conversions
	MAKEPR,
	MAKPR1,
	NEGFLG,
%4517%	NEWENTRY,	! Makes a new entry in a table
	NOTFLG,
%4517%	ONEPLIT,	! Constant table entry for 1
%4517%	P2SILF,		! Checks for inline functions that can be folded
	P2SKARITH,
	P2SKBL,
%4517%	SINGLECHARCHK,	! Checks to see if we have a single character express
	P2SKFN,
%2272%	P2SKFOLD,	! Folds top-level concatenation nodes
	P2SKL1DISP,
	P2SKLARR,
	P2SKLTP,
	P2SKNEGNOT,
%2304%	P2SKOVRLP,	! Handles compile-time overlap tests
	P2SKREL,
%4517%	SAVSPACE,
	SKERR,
	SKIOLIST,
	SKOPTIO,
	TBLSEARCH,
%1530%	TOPIO,		! Pointer to the top level I/O statement
%1530%			! above an IOLSCLS node
	UNFLDO,		! Undo decision to have a do loop use AOBJN in UTIL
	USERFNFLG;	! Flag set for statement that includes user functions

MACRO SKIOLST=
%1742%	! Do skeleton optimizations for IOLIST if specified

	IF .CSTMNT[IOLIST] NEQ 0
	THEN IF .FLGREG<OPTIMIZE>
	THEN SKOPTIO()		! Optimized skeleton for IOLIST
	ELSE SKIOLIST()$;	! non-optimized skeleton for IOLIST

MACRO SKWALK(X)=
%1742%	! Do skeleton optimization for an expression

%1742%	BEGIN
%1742%		CNODE = .X;	! Get expression

%1742%		! If non-zero, call the appropriate skeleton routine

%1742%		IF .CNODE NEQ 0
%1742%		THEN X = (.P2SKL1DISP[.CNODE[OPRCLS]])(.CNODE)
%1742%	END$;

GLOBAL ROUTINE P2SKSTMNT=
BEGIN
	!***************************************************************
	! Perform  phase  2  skeleton  optimizations  on  the  statement
	! pointed to by the global CSTMNT.
	!***************************************************************

	%(***AT START OF A STMNT, CAN INIT NEGFLG AND NOTFLG TO FALSE***)%
	NEGFLG_FALSE;
	NOTFLG_FALSE;

	USERFNFLG_FALSE;	!FLAG FOR "STMNT INCLUDES USER FNS" - INIT TO FALSE
	%(***PROCESS THIS STMNT IN A MANNER DETERMINED BY ITS SRCID***)%
	CASE .CSTMNT[SRCID] OF SET

	SKASMNT();		! ASSIGNMENT
	SKASSI();		! ASSIGN
	SKCALL();		! CALL
	BEGIN END;		! CONTINUE (DO NOTHING)
	DOP2SKL();		! DO
	BEGIN END;		! ENTRY (DO NOTHING)
	SKASMNT();		! COMNSUB (SAME AS ASSIGNMENT IN FORMAT)

	BEGIN END;		! GOTO
	SKAGO();		! ASSIGNED GOTO
	SKCGO();		! COMPUTED GOTO
	SKARIF();		! ARITHMETIC IF
	SKLOGIF();		! LOGICAL IF
	SKRETURN();		! RETURN
	BEGIN END;		! STOP

	BEGIN			! READ
%1530%		TOPIO = .CSTMNT;	! Pointer to top level I/O statement
%1516%		SKIO(TRUE);
	END;			! READ

	BEGIN			! WRITE
%1530%		TOPIO = .CSTMNT;	! Pointer to top level I/O statement
%1516%		SKIO(FALSE);
	END;			! WRITE

	BEGIN			! DECODE
%1530%		TOPIO = .CSTMNT;	! Pointer to top level I/O statement
%1742%		SKDECENC(TRUE);
	END;			! DECODE

	BEGIN			! ENCODE
%1530%		TOPIO = .CSTMNT;	! Pointer to top level I/O statement
%1742%		SKDECENC(FALSE);
	END;			! ENCODE

	BEGIN			! REREAD
%1530%		TOPIO = .CSTMNT;	! Pointer to top level I/O statement
%1742%		SKIO(TRUE)
	END;			! REREAD

	BEGIN			! FIND
%1742%		SKIO(FALSE);
	END;			! FIND

	BEGIN			! CLOSE
%1530%		TOPIO = .CSTMNT;	! Pointer to top level I/O statement
%1527%		SKOPNCLS();
	END;			! CLOSE

%4502%	SKIO(FALSE);		! DELETE
%4503%	SKIO(FALSE);		! REWRITE
%1742%	SKIO(FALSE);		! BACKSPACE
%1742%	SKIO(FALSE);		! BACKFILE
%1742%	SKIO(FALSE);		! REWIND
%1742%	SKIO(FALSE);		! SKIP FILE
%1742%	SKIO(FALSE);		! SKIP RECORD
%1742%	SKIO(FALSE);		! UNLOAD
%4504%	SKIO(FALSE);		! UNLOCK
%1742%	SKIO(FALSE);		! ENDFILE

	BEGIN END;		! END
	BEGIN END;		! PAUSE

	BEGIN			! OPEN
%1530%		TOPIO = .CSTMNT;	! Pointer to top level I/O statement
%1527%		SKOPNCLS();
	END;			! OPEN

	SKSFN();		! SFN
	BEGIN END;		! FORMAT
	BEGIN END;		! BLT
	BEGIN END;		! REGMASK - change set of available registers -
				!  inserted by global register allocator
%2200%	BEGIN			! INQUIRE
%2200%		TOPIO = .CSTMNT;	! Pointer to top level I/O statement
%2200%		SKOPNCLS();
%2200%	END;			! INQUIRE

	TES;

	%(***IF THIS STMNT CONTAINED A USER FN, SET FLAG IN STMNT**)%
	IF .USERFNFLG THEN CSTMNT[USRFNREF]_1;


	%(***IF ARE IN AN INNERMOST DO LOOP, CHECK FOR CONDITIONS THAT PREVENT
		THE LOOP INDEX FROM BEING MAINTAINED IN A REGISTER, OR FROM BEING
		HANDLED WITH AN AOBJN***)%
	IF .INNERLOOP
	THEN
	BEGIN
		P2REGCNTS();
		IF .CSTMNT[SRCLBL] NEQ 0	! IF THIS STMNT HAD A LABEL
		THEN DOENSKL();			! CHECK FOR THE END OF THE LOOP
	END;
END;	! of P2SKSTMNT

GLOBAL ROUTINE SKASMNT=
!++
!***********************************************************************
! Perform phase 2 skeleton optimizations on an assignment statement.
!
! The global CSTMNT contains the assignment statement to optimize.
!***********************************************************************
!--
BEGIN
	REGISTER
		PEXPRNODE RHNODE,
		PEXPRNODE LHNODE,
		PEXPRNODE SSNODE;


	%(***PROCESS RIGHT HAND SIDE***)%
	IF NOT .CSTMNT[A2VALFLG]
	THEN
	BEGIN
		RHNODE_.CSTMNT[RHEXP];
		NEGFLG_FALSE;
		NOTFLG_FALSE;
		CSTMNT[RHEXP]_(.P2SKL1DISP[.RHNODE[OPRCLS]])(.RHNODE);
		IF .NEGFLG THEN
		 CSTMNT[A2NEGFLG]_NOT .CSTMNT[A2NEGFLG];	!IF A NEG IS PROPAGATED FROM BELOW,
								! COMPLEMENT THE NEGFLG IN THE STMNT NODE

		IF .NOTFLG THEN			!IF A NOT IS PROPAGATED UP FROM BELOW
		 CSTMNT[A2NOTFLG]_NOT .CSTMNT[A2NOTFLG];	! COMPLEMENT THE NOT FLAG IN THE STMNT
	END;

	! Process left hand side - it must be either a simple variable,
	! or an array reference

	IF NOT .CSTMNT[A1VALFLG]
	THEN
	BEGIN	! Left had side not a leaf, must be an array reference

		LHNODE_.CSTMNT[LHEXP];
		IF .LHNODE[OPRCLS] NEQ ARRAYREF THEN RETURN CGERR();

		! Optimize address calculation.

		IF NOT .LHNODE[A2VALFLG]
		THEN
		BEGIN	! Address calculation not leaf
			SSNODE_.LHNODE[ARG2PTR];
			NEGFLG_FALSE;
			NOTFLG_FALSE;
			LHNODE[ARG2PTR]_(.P2SKL1DISP[.SSNODE[OPRCLS]])(.SSNODE);
			IF .NEGFLG THEN LHNODE[A2NEGFLG]_1;
			IF .NOTFLG THEN LHNODE[A2NOTFLG]_1;

		END;	! Address calculation not leaf

%2243%		! If a numeric array reference is:
%2243%		!
%2243%		!	o in an innermost DO loop,
%2243%		!	o and the array is in PSLARGE,
%2243%		!	o and the index variable for the DO is in  the
%2243%		!	  address calculation for the array,
%2243%		!
%2243%		! then mark that this  should not be an AOBJN loop.
%2243%
%2243%		IF .INNERLOOP
%2243%		THEN ARNOAOBJN(.LHNODE);

	END;	! Left had side not a leaf

	%(***IF THE VAR ON THE LEFT HAND SIDE OF THIS ASSIGNMENT STMNT IS EQUAL
		TO THE DO INDEX OF THE CURRENT DO LOOP, DONT WANT TO USE AOBJN
		IF THE INDEX IS NOT MATERIALIZED***)%
	IF .DOWDP[DOINDUC] EQL .CSTMNT[LHEXP] THEN DOWDP[DONOAOBJN]_1;

	%(**IF LHS=RHS, CHANGE THIS TO A CONTINUE**)%
	IF .CSTMNT[LHEXP] EQL .CSTMNT[RHEXP]
	 	AND (.CSTMNT[A1NGNTFLGS] EQL 0)
	AND (.CSTMNT[A2NGNTFLGS] EQL 0)
	THEN CSTMNT[SRCID]_CONTID;

END;	! of SKASMNT

GLOBAL ROUTINE SKSFN=
BEGIN

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

	! Perform phase 2 skeleton optimizations on the expression under
	! a statement function.  The expression is either an  assignment
	! node for  numeric  statement  functions or  a  call  node  for
	! character statement functions.

	REGISTER OCSTMNT;
	REGISTER BASE FNID;

	NEGFLG = FALSE;		! Init flags for propagating negates and nots
	NOTFLG = FALSE;

	OCSTMNT = .CSTMNT;	! Save away a pointer to the current statement

	FNID = .CSTMNT[SFNNAME];	! Get the symbol table entry for the
					! function name

	CSTMNT = .CSTMNT[SFNEXPR];	! Get the expression

	IF .FNID[VALTYPE] EQL CHARACTER
	THEN	SKCALL()
	ELSE	SKASMNT();

	CSTMNT = .OCSTMNT;	! Restore the pointer to the current statement

END;	! of SKSFN

GLOBAL ROUTINE SKRETURN=
%(***************************************************************************
	PERFORM P2SKEL OPS ON THE EXPR UNDER A RETURN STMNT
***************************************************************************)%
BEGIN
	REGISTER PEXPRNODE RHNODE;
	IF (RHNODE_.CSTMNT[RETEXPR]) NEQ 0 THEN
	CSTMNT[RETEXPR]_(.P2SKL1DISP[.RHNODE[OPRCLS]])(.RHNODE);
END;	! of SKRETURN

GLOBAL ROUTINE SKAGO=
%(***************************************************************************
	ROUTINE TO PERFORM PHASE 2 SKEL OPTIMS ON AN ASSIGNED GOTO.
	OPTIMS MAY BE PERFORMED ON THE ADDRESS CALC FOR THE ASSIGNED VAR
	(WHICH MAY BE AN ARRAY REF)
***************************************************************************)%
BEGIN
	REGISTER PEXPRNODE AGOVAR;

	AGOVAR_.CSTMNT[AGOTOLBL];

	IF .AGOVAR[OPRCLS] EQL ARRAYREF
	THEN
	CSTMNT[AGOTOLBL]_(.P2SKL1DISP[.AGOVAR[OPRCLS]])(.AGOVAR);

END;	! of SKAGO

GLOBAL ROUTINE SKCGO=
%(***************************************************************************
	ROUTINE TO PERFORM PHASE 2 SKELETON OPTIMIZATIONS ON A
	COMPUTED GOTO STATEMENT.
	PERFORM OPTIMIZATIONS ON THE COMPUTED EXPRESSION, AND THEN IF
	THE EXPRESSION COLLAPSES TO A CONSTANT, TRANSFORM THE STMNT
	TO A GOTO.
***************************************************************************)%
BEGIN
	REGISTER PEXPRNODE CGOEXP;

	CGOEXP_.CSTMNT[CGOTOLBL];

	%(***PERFORM PHASE 2 SKEL OPTIMS ON THE COMPUTED EXPRESSION***)%
	IF .CGOEXP[OPRCLS] NEQ DATAOPR
	THEN
	CGOEXP_(.P2SKL1DISP[.CGOEXP[OPRCLS]])(.CGOEXP);

	%(***IF EXPRESSION HAS REDUCED TO A CONSTANT, CHANGE STMNT TO A GOTO**)%
	IF .CGOEXP[OPR1] EQL CONSTFL
	THEN
	BEGIN
		DELGOLABS(.CSTMNT);	!DECR THE REF CTS FOR ALL LABELS ON THE LIST 
		CSTMNT[SRCID]_GOTOID;
		%(***GET PTR TO THE LABEL TO BE USED (THE CONSTANT MUST ALWAYS BE
			INTEGER)****)%

		IF .CGOEXP[CONST2] GEQ .CSTMNT[GOTONUM] OR .CGOEXP[CONST2] LEQ 0
		THEN
		%(***IF CONSTANT IS LARGER THAN NUMBER OF LABELS IN LIST, OR LESS THAN 0***)%
		CSTMNT[SRCID]_CONTID	!CHANGE IT TO A CONTINUE
		ELSE
		BEGIN
			REGISTER PEXPRNODE LABENTRY;	!PTR TO  STMNT NUMBER TABLE ENTRY
							! FOR THE LABEL TO BE USED ON THE "GOTO"
			LABENTRY_@(.CSTMNT[GOTOLIST]+.CGOEXP[CONST2]-1);
			CSTMNT[GOTOLBL]_.LABENTRY;

			LABENTRY[SNREFNO]_.LABENTRY[SNREFNO]+1;	!INCR REF CT FOR THE LABEL USED
							! (HAD PREVIOUSLY DECR'D IT WITH ALL THE OTHERS)
		END;

	END

	ELSE
	BEGIN
		CSTMNT[CGOTOLBL]_.CGOEXP;

		%(***CHECK FOR THE "COMPUTED" VAR EQUAL TO THE DO-LOOP INDEX.
			IF IT IS, THEN THIS DO LOOP SHOULD NOT USE AOBJN***)%
		IF .CGOEXP EQL .DOWDP[DOINDUC]
		THEN DOWDP[DONOAOBJN]_1;
	END;
END;	! of SKCGO

GLOBAL ROUTINE DELGOLABS(GOSTMNT)=
%(***************************************************************************
	ROUTINE TO DECREMENT THE REFERENCE CT FOR EACH LABEL ON A COMPUTED
	GOTO LIST. THIS ROUTINE MUST BE CALLED WHENEVER A COMPUTED GOTO
	IS OPTIMIZED OUT OF A PROGRAM.
	CALLED WITH THE ARG "GOSTMNT" POINTING TO THE COMPUTED GOTO STMNT.
***************************************************************************)%
BEGIN
	MAP BASE GOSTMNT;
	REGISTER CGOLISTPTR;	!PTR TO ELEMS ON CGOTO LIST
	REGISTER PEXPRNODE LABENTRY;	!PTR TO STMNT NUMBER TABLE ENTRY
					! FOR A LABEL ON THE CGOTO LIST

	CGOLISTPTR_.GOSTMNT[GOTOLIST];
	DECR CT FROM (.GOSTMNT[GOTONUM]-1) TO 0	!LOOK AT EACH LABEL ON LIST
	DO
	BEGIN
		[email protected];	!STMNT NUMBER TABLE ENTRY FOR THIS LABEL
		LABENTRY[SNREFNO]_.LABENTRY[SNREFNO]-1;	!DECR REF CT FOR THIS LABEL
		CGOLISTPTR_.CGOLISTPTR+1;	!GO ON TO NEXT ELEM ON LIST
	END;
END;	! of DELGOLABS

GLOBAL ROUTINE SKLOGIF=
%(***************************************************************************
	PERFORM PHASE 2 SKELETON OPTIMIZATIONS ON A LOGICAL IF STATEMENT
	CALLED WITH THE GLOBAL "CSTMNT" POINTING TO THE STATEMENT.
***************************************************************************)%
BEGIN
	REGISTER
		PEXPRNODE CONDEXPR,
		BASE SAVSTMNT;		! SAVE PTR TO THIS STMNT WHILE PROCESS
					! THE SUB-STATEMNET

	%(***PERFORM PHASE 2 SKELETON ON THE CONDITIONAL EXPRESSION***)%
	CONDEXPR_.CSTMNT[LIFEXPR];
	CONDEXPR_(.P2SKL1DISP[.CONDEXPR[OPRCLS]])(.CONDEXPR);
	CSTMNT[LIFEXPR]_.CONDEXPR;
	%(***IF PROPAGATED A NOT BACK UP FROM THE CONDITIONAL EXPR***)%
	IF .NOTFLG
	THEN CSTMNT[A1NOTFLG]_1;

	%(***IF CONDEXPR IS A CONSTANT, CHANGE THE LOGIF TO A CONTINUE FOLLOWED BY 
		THE SUBSTATEMENT****)%
	IF .CONDEXPR[OPR1] EQL CONSTFL
	THEN
	BEGIN
		FOLDLIF();
		RETURN;
	END

	%(***IF THE "CONDITIONAL EXPRESSION" IS SIMPLY THE LOOP INDEX OF THE INNERMOST
		EMBRACING DO LOOP, DO NOT WANT TO USE AOBJN FOR THAT DO LOOP***)%
	ELSE
	IF .CONDEXPR EQL .DOWDP[DOINDUC] THEN DOWDP[DONOAOBJN]_1;



	%(***PERFORM PHASE 2 SKELETON OPTIMIZATIONS ON THE SUBSTATEMENT ***)%
	SAVSTMNT_.CSTMNT;
	CSTMNT_.CSTMNT[LIFSTATE];

	%(***IF THE SUBSTATEMENT IS 'CONTINUE' CAN ELIMINATE THE CONDITIONAL ALTOGETHER***)%
	P2SKSTMNT();

	CSTMNT_.SAVSTMNT;
END;	! of SKLOGIF

GLOBAL ROUTINE SKARIF=
%(***************************************************************************
	PERFORM PHASE 2 SKELETON OPTIMIZATIONS ON AN ARITHMETIC IF
	STATEMENT.
	CALLED WITH THE GLOBAL CSTMNT POINTING TO THE STATEMENT.
***************************************************************************)%
BEGIN
	REGISTER
		PEXPRNODE CONDEXPR,	! THE CONDITIONAL EXPR UNDER THE STMNT
		BASE GONODE1,
		BASE GONODE2,
		RELOPERATOR;

	LOCAL
		PEXPRNODE ARG1NODE,	! THE 2 ARGS UNDER CONDEXPR
		PEXPRNODE ARG2NODE,
		PEXPRNODE RPTLBL,	! THE LABEL THAT OCCURS TWICE IN THIS
				! STMNT (IF ANY 2 OF THE 3 LABELS ARE THE SAME)
		SAVSTMN;	! Save CSTMNT

	CONDEXPR_.CSTMNT[AIFEXPR];

	%(***PERFORM PHASE 2 SKEL OPTIMIZ'S ON THE ARITH EXPRESSION UNDER THIS IF STMNT***)%

	CONDEXPR_(.P2SKL1DISP[.CONDEXPR[OPRCLS]])(.CONDEXPR);

	CSTMNT[AIFEXPR]_.CONDEXPR;
	CSTMNT[A1NEGFLG]_.NEGFLG<0,1>;

	%(***IF THE CONDITIONAL EXPRESSION IS A CONSTANT, CHANGE THE ARIF INTO A GOTO***)%
	IF .CONDEXPR[OPR1] EQL CONSTFL
	THEN
	BEGIN
		FOLDAIF();
		RETURN;
	END

	%(***IF THE "CONDITIONAL EXPRESSION" IS SIMPLY THE DO LOOP INDEX,
		DO NOT KEEP THAT INDEX IN THE RIGHT HALF OF AN AOBJN WD***)%
	ELSE
	IF .CONDEXPR EQL .DOWDP[DOINDUC] THEN DOWDP[DONOAOBJN]_1;




	%(***DETERMINE WHICH (IF ANY) OF THE 3 LABELS ON THE IF ARE IDENTICAL TO EACHOTHER***)%
	IF .CSTMNT[AIFLESS] EQL .CSTMNT[AIFEQL]
	THEN
	BEGIN
		%(***IF ALL 3 LABELS ARE IDENTICAL - MAKE THIS NODE BE A GOTO***)%
		IF .CSTMNT[AIFLESS] EQL .CSTMNT[AIFGTR]
		THEN
		BEGIN
%1050%			IF NOT .USERFNFLG THEN
%1050%			BEGIN	! Expression must not contain function calls
%1050%				CSTMNT[SRCID]_GOTOID;
%1050%				CSTMNT[GOTOLBL]_.CSTMNT[AIFLESS];
%1050%				RPTLBL_.CSTMNT[AIFLESS];
%1050%				RPTLBL[SNREFNO]_.RPTLBL[SNREFNO]-2
%1050%			END
		END

		ELSE
		CSTMNT[AIFLBEQV]_LELBEQV
	END

	ELSE
	IF .CSTMNT[AIFGTR] EQL .CSTMNT[AIFEQL]
	THEN
	CSTMNT[AIFLBEQV]_GELBEQV

	ELSE
	IF .CSTMNT[AIFLESS] EQL .CSTMNT[AIFGTR]
	THEN
	CSTMNT[AIFLBEQV]_LGLBEQV

	ELSE
	CSTMNT[AIFLBEQV]_NOLBEQV;


	%(***CHECK FOR THE ARITH EXPR A SUM OR DIFFERENCE - THEN
		IF OPERATION IS NOT DOUBLE-PREC WE WILL WANT TO GENERATE
		CODE TO TEST THE RELATION OF THE 2 TERMS UNDER THE SUM/DIFFERENCE
		RATHER THAN COMPUTING THE VALUE OF IT (WHEN
		ANY 2 OF THE 3 LABELS ARE IDENTICAL)****)%
	IF ADDORSUB(CONDEXPR) AND (NOT .CONDEXPR[DBLFLG]) AND (.CSTMNT[AIFLBEQV] NEQ NOLBEQV)
		AND (.CSTMNT[SRCLINK] NEQ 0)	!IF THIS ARITH IF IS THE TRUE BRANCH
						! UNDER A LOGICAL IF, CANNOT TRANSFORM
						! THIS ARITH IF TO A LOG IF
	THEN
	BEGIN
		%(***WANT TO TRANSFORM THE ARITHMETIC TO A LOGICAL IF-GOTO, FOLLOWED BY A GOTO***)%

		CSTMNT[SRCID] = IFLID;

%1530%		NAME<LEFT> = SRCSIZ + GOTOSIZ;
		GONODE1 = CORMAN();
		GONODE1[OPRCLS] = STATEMENT;
		GONODE1[SRCID] = GOTOID;
%1530%		NAME<LEFT> = SRCSIZ + GOTOSIZ;
		GONODE2 = CORMAN();
		GONODE2[OPRCLS] = STATEMENT;
		GONODE2[SRCID] = GOTOID;

		%(***DETERMINE WHAT RELATIONAL TO SUBSTITUTE FOR THE ARITHMETIC OPERATOR
			AND WHICH LABELS TO PUT ON EACH OF THE "GOTO"S***)%
		CASE .CSTMNT[AIFLBEQV] OF SET
		%(***IF NONE OF THE 3 LABELS ARE IDENTICAL, HAVE AN ERROR***)%
		CGERR();

		%(***IF LESS LABEL SAME AS EQL LABEL***)%
		BEGIN
			RELOPERATOR_LE;		!RELATIONAL BECOMES LE
			GONODE1[GOTOLBL]_.CSTMNT[AIFLESS];	!WHEN REL IS TRUE, GO
						! LABEL FOR LESS OR EQ
			GONODE2[GOTOLBL]_.CSTMNT[AIFGTR];
		END;

		%(***FOR LESS LABEL SAME AS GTR LABEL***)%
		BEGIN
			RELOPERATOR_N;		!RELATIONAL BECOMES NE
			GONODE1[GOTOLBL]_.CSTMNT[AIFLESS];	!WHEN REL IS TRUE, GOTO
						! LABEL FOR GTR OR LESS
			GONODE2[GOTOLBL]_.CSTMNT[AIFEQL];
		END;

		%(***FOR GTR LABEL SAME AS EQL LABEL***)%
		BEGIN
			RELOPERATOR_GE;		!RELATIONAL BECOMES GE
			GONODE1[GOTOLBL]_.CSTMNT[AIFGTR];	!WHEN REL IS TRUE, GOTO
						! LABEL FOR GTR  OR EQL
			GONODE2[GOTOLBL]_.CSTMNT[AIFLESS];
		END;
		TES;

		%(***FOR THE LABEL THAT OCCURED TWICE IN THE ORIGINAL STMNT,
			MUST DECREMENT THE REFERENCE COUNT SINCE IT IS NOW REFERENCED
			ONLY ONCE IN THE LOGICAL IF***)%
		RPTLBL_.GONODE1[GOTOLBL];
		RPTLBL[SNREFNO]_.RPTLBL[SNREFNO]-1;

		%(***IF ARITHMETIC EXPR WAS (A-B),  WILL WANT THE REALATIONAL
			A.RELAOPERATOR.B 
			TURN OFF THE NEGATE-FLAG ON ARG2
		*****)%
		IF .CONDEXPR[A2NEGFLG]
		THEN CONDEXPR[A2NEGFLG]_0

		ELSE
		%(***IF ARITHMETIC EXPRESSION WAS (A+B), THEN THE
			RELATIONAL IS OF THE FORM:
			A.RELAOPERATOR.(-B)
			SINCE WE CANNOT HANDLE AN A2NEGFLG ON A RELATIONAL WE 
			WILL EITHER:
				1. IF B IS A CONSTANT, NEGATE IT
			   OR	2. MULTIPLY THE RELATIONAL BY -1
		*******)%
		BEGIN
			ARG2NODE_.CONDEXPR[ARG2PTR];
			IF .ARG2NODE[OPR1] EQL CONSTFL
			THEN CONDEXPR[ARG2PTR]_NEGCNST(ARG2NODE)
			ELSE
			BEGIN
				%(**NEGATE THE 1ST ARG***)%
				ARG1NODE_.CONDEXPR[ARG1PTR];
				IF .ARG1NODE[OPR1] EQL CONSTFL
				THEN CONDEXPR[ARG1PTR]_NEGCNST(ARG1NODE)
				ELSE CONDEXPR[A1NEGFLG]_NOT .CONDEXPR[A1NEGFLG];

				%(***REVERSE THE SENSE OF THE RELATIONAL IF IT IS GE OR LE***)%
				IF .RELOPERATOR EQL LE THEN RELOPERATOR_GE
				ELSE
				IF .RELOPERATOR EQL GE THEN RELOPERATOR_LE;
			END;
		END;
		%(***TRANSFORM THE CONDEXPR INTO A RELATIONAL***)%
		CONDEXPR[OPERATOR]_OPERC(CONTROL,RELATIONAL,.RELOPERATOR);

		%(***TRANSFORM THE ARITH-IF STMNT INTO A LOGICAL IF***)%
		CSTMNT[SRCID]_IFLID;
		CSTMNT[AIFLBEQV]_0;
		CSTMNT[LIFSTATE]_.GONODE1;

		SAVSTMN_.CSTMNT;
		CSTMNT_.GONODE1;	!CALL P2SKSTMN FOR THE GOTO NODE THAT
		P2SKSTMNT();		! IS UNDER THE LOGICAL IF, SO THAT P2REGCNTS
					! WILL BE CALLED FOR IT AND ITS LABEL
					! CHECKED FOR A TRANSFER OUT THE CURRENT LOOP
		CSTMNT_.SAVSTMN;


		%(**INSERT THE EXTRA GOTO INTO THE PROGRAM***)%
		GONODE2[CLINK]_.CSTMNT[CLINK];
		CSTMNT[CLINK]_.GONODE2;

	END;

END;	! of SKARIF

GLOBAL ROUTINE SKASSI=
%(***************************************************************************
	TO PERFORM PHASE 2 SKEL OPTIMS ON AN ASSIGN STMNT.
	IF THE VAR ASSIGNED TO IS AN ARRAYREF, THERE MAY BE SOME OPTIMS THAT
	CAN BE PERFORMED ON THE ADDRESS ARITH.
***************************************************************************)%
BEGIN
	REGISTER PEXPRNODE SYMNODE;
	SYMNODE_.CSTMNT[ASISYM];
	IF .SYMNODE[OPRCLS] EQL ARRAYREF
	THEN P2SKLARR(.SYMNODE);
END;	! of SKASSI

ROUTINE SKIO(INPFLG)=
BEGIN
! [1516] New
! Phase 2 skeleton optimizations on READ/WRITE (etc.) statements

	REGISTER PEXPRNODE CNODE;

%1742%	SKWALK(CSTMNT[IOUNIT]);
%1742%	SKWALK(CSTMNT[IORECORD]);
%1742%	SKWALK(CSTMNT[IOIOSTAT]);
%4501%	IF (.CSTMNT[SRCID] EQL READID)
%4501%	THEN SKWALK(CSTMNT[IOKEY]);

%2365%	! Check for inner DO-variable as keyword value
%2365%
%2365%	IF .CSTMNT[IOUNIT] EQL .DOWDP[DOINDUC]
%2365%		OR .CSTMNT[IORECORD] EQL .DOWDP[DOINDUC]
%2365%		OR .CSTMNT[IOIOSTAT] EQL .DOWDP[DOINDUC]
%4501%		OR .CSTMNT[IOKEY]    EQL .DOWDP[DOINDUC]
%2365%	THEN DOWDP[DONOAOBJN] = 1;	! don't use AOBJN

%1742%	IF .CSTMNT[IOFORM] NEQ #777777
%1742%	THEN SKWALK(CSTMNT[IOFORM]);	! Not list-directed I/O

	INPFLAG = .INPFLG;
	SKIOLST;		! Do skeleton opts on IOLIST
END;	! of SKIO

GLOBAL ROUTINE SKDECENC(INPFLG)=
BEGIN
	!***************************************************************
	! Perform  phase  2  skeleton  optimizations  on   ENCODE/DECODE
	! statements.
	!***************************************************************

	REGISTER PEXPRNODE CNODE;

%1742%	! Check for do index variables as keyword values

	IF .CSTMNT[IOVAR] EQL .DOWDP[DOINDUC]
	   OR .CSTMNT[IOCNT] EQL .DOWDP[DOINDUC]
%1742%	   OR .CSTMNT[IOIOSTAT] EQL .DOWDP[DOINDUC]
	THEN DOWDP[DONOAOBJN] = 1;	! don't use AOBJN

	CNODE = .CSTMNT[IOVAR];

	%(***OF THE ENCODE/DECODE ARRAY IS ACTUALLY AN ARRAYREF NODE (IE
		IT INCLUDES AN OFFSET) PERFORM P2SKEL OPTIMS  ON THE ADDR
		CALC****)%
	IF .CNODE[OPRCLS] EQL ARRAYREF
	THEN CSTMNT[IOVAR]_P2SKLARR(.CNODE);

%1742%	SKWALK(CSTMNT[IOCNT]);		! Do skeleton opts on count
%1742%	SKWALK(CSTMNT[IOIOSTAT]);	! Do skeleton opts on IOSTAT

%1742%	IF .CSTMNT[IOFORM] NEQ #777777
%1742%	THEN SKWALK(CSTMNT[IOFORM]);	! Not list-directed I/O

%1742%	INPFLAG = .INPFLG;
%1742%	SKIOLST;		! Do skeleton opts on IOLIST

END;	! of SKDECENC

ROUTINE SKOPNCLS=
BEGIN
%1527%	! New
%2200%	! Do  phase   2   skeleton   optimizations   on   arguments   of
%2200%	! OPEN/CLOSE/INQUIRE statement.

	REGISTER
		PEXPRNODE CNODE,
%4500%		OPNKEYLIST KEYL,	!list of keys
%1742%		OPENLIST OPENL;

%1742%	SKWALK(CSTMNT[IOUNIT]);		! walk unit expression if specified
%1742%	SKWALK(CSTMNT[IOIOSTAT]);	! walk iostat expression if specified
%2200%	SKWALK(CSTMNT[IOFILE]);		! walk file expression if specified

%2365%	! Check for inner DO-variable as keyword value
%2365%
%2365%	IF .CSTMNT[IOUNIT] EQL .DOWDP[DOINDUC]
%2365%		OR .CSTMNT[IOIOSTAT] EQL .DOWDP[DOINDUC]
%2365%	THEN DOWDP[DONOAOBJN] = 1;	! don't use AOBJN

%1742%	OPENL = .CSTMNT[OPLST];		! walk other args in the keyword list
%1742%	DECR I FROM .CSTMNT[OPSIZ] - 1 TO 0 DO
%1742%	BEGIN
%1742%		SKWALK(OPENL[.I,OPENLPTR]);	! Walk expression if not 0
%1742%					! i.e. DIALOG, READONLY
%1742%
%1742%		! Check for do index variable as argument
%1742%		IF .OPENL[.I,OPENLPTR] EQL .DOWDP[DOINDUC]
%1742%		THEN DOWDP[DONOAOBJN] = 1;	! don't use AOBJN
%1742%	END;
%4500%	IF (KEYL = .CSTMNT[IOKEY]) NEQ 0
%4500%	THEN	! there are keys
%4500%	BEGIN
%4500%		INCR I FROM 1 TO .KEYL[NUMKEYS] DO
%4500%		BEGIN
%4500%			! Walk down expression for lower bound of key
%4500%			! and check do index variable as argument
%4500%
%4500%			SKWALK(KEYL[.I,KEYLOW]);
%4500%
%4500%			IF .KEYL[.I,KEYLOW] EQL .DOWDP[DOINDUC]
%4500%			THEN DOWDP[DONOAOBJN] = 1;	! Don't use AOBJN
%4500%
%4500%			! Walk down expression for upper bound of key
%4500%			! and check do index variable as argument
%4500%
%4500%			SKWALK(KEYL[.I,KEYHIGH]);
%4500%
%4500%			IF .KEYL[.I,KEYHIGH] EQL .DOWDP[DOINDUC]
%4500%			THEN DOWDP[DONOAOBJN] = 1;	! Don't use AOBJN
%4500%		END;
%4500%	END;			
END;	! of SKOPNCLS

GLOBAL ROUTINE SKCALL=
%(***************************************************************************
	PERFORM PHASE 2 SKEL OPTIMIZS ON ALL ARGS OF A CALL STMNT
***************************************************************************)%
BEGIN
	REGISTER
%4517%		ARGUMENTLIST ARGLST:ALST,
%4527%		BASE ARGNODE;			! Argument node
%4517%	LOCAL	BASE NODE:TMP;
	ARGLST_.CSTMNT[CALLIST];		!PTR TO ARG LIST

	%(***IF THERE ARE NO ARGS, RETURN***)%
%4517%	IF .ARGLST[ARGCOUNT] EQL 0 THEN RETURN;

	%(***WALK THRU THE ARGS***)%
	INCR CT FROM 1 TO .ARGLST[ARGCOUNT]
	DO
	BEGIN
		IF NOT .ARGLST[.CT,AVALFLG]
		THEN
%2272%		BEGIN	! Arg is an expression
%2272%
%2272%			ARGNODE = .ARGLST[.CT,ARGNPTR];	! Get ptr to this arg
%2272%
%2272%			! Perform skeleton optimizations on this argument.
%2272%
%2272%			NEGFLG = FALSE;
%2272%			NOTFLG = FALSE;
%2272%			ARGLST[.CT,ARGNPTR] = ARGNODE =
%2272%				(.P2SKL1DISP[.ARGNODE[OPRCLS]])(.ARGNODE);
%2272%
%2272%			IF .ARGNODE[OPRCLS] EQL DATAOPR
%2272%			THEN ARGLST[.CT,AVALFLG] = 1;
%2272%
%2272%		END;	! Arg is an expression
	END;

%2272%	ARGNODE = .CSTMNT[CALSYM];	! Get sym table entry for routine name
%4527%	ARGNODE = .ARGNODE[ID1ST6CHAR];	! Get sixbit routine name
%2272%
%4517%	! If we have a single character assignment we should generate an
%4517%	! inline character assignment
%4517%
%4517%	NODE = .ARGLST[2,ARGNPTR];
%4517%	IF SINGLECHARCHK(.ARGLST[1,ARGNPTR]) ! assigning into a single char
%4517%	THEN IF (.ARGNODE EQL SIXBIT 'CASNN.' OR .ARGNODE EQL SIXBIT 'CASNM.'
%4517%	OR 	.ARGNODE EQL SIXBIT 'CNCAN.' OR .ARGNODE EQL SIXBIT 'CNCAM.'
%4517%	OR 	.ARGNODE EQL SIXBIT 'CASNO.' OR .ARGNODE EQL SIXBIT 'CASAO.')
%4517%	THEN
%4517%	BEGIN
%4517%		! Convert Call statement node into assignment stm
%4517%		!
%4517%		!	  call stmn			  assignment
%4517%		!	   /     \			  /	  \
%4517%		!	routine  arglist	=>    inlinfn   inlinfn
%4517%		!	name      /   \		       CHAR      ICHAR
%4517%		!	       arg1   arg2	        /         /
%4517%		!                                     arg1      arg2
%4517%	
%4517%		INCR CT FROM 1 TO .ARGLST[ARGCOUNT]
%4517%		DO
%4517%		BEGIN
%4517%			ARGNODE = .ARGLST[.CT,ARGNPTR];
%4517%
%4517%			! convert char const to integer constant
%4517%			IF .ARGNODE[OPR1] EQL CONSTFL
%4517%			THEN ARGLST[.CT,ARGNPTR] = MAKECNST(INTEGER,0,.ARGNODE[LITC2])
%4517%			
%4522%			! If we have a non-dummy substring/arrayref then
%4517%			! Change arg2ptr to lower bound instead of lower bound-1	
%4517%			! Change arg2ptr to array offset instead of array offset-1
%4517%			ELSE IF .ARGNODE[OPRCLS] EQL SUBSTRING
%4517%			     OR .ARGNODE[OPRCLS] EQL ARRAYREF
%4517%			THEN
%4517%			BEGIN
%4522%				IF NOT ISDUMMY(ARGNODE)
%4522%				THEN
%4522%				BEGIN
%4517%					ARGNODE[A2VALFLG] = 0;
%4517%					ARGNODE[ARG2PTR] = NODE = MAKPR1(.ARGNODE,ARITHMETIC,ADDOP,INTEGER,.ARGNODE[ARG2PTR],.ONEPLIT);
%4517%					ARGNODE[ARG2PTR] = NODE = (.P2SKL1DISP[.NODE[OPRCLS]])(.NODE);
%4517%					IF .NODE[OPRCLS] EQL DATAOPR
%4517%					THEN ARGNODE[A2VALFLG] = 1
%4517%					ELSE NODE[PARENT] = .ARGNODE;
%4517%				END
%4517%			END
%4517%		END;
%4517%
%4517%		IF ASGNSIZ NEQ CALLSIZ THEN CGERR(); ! assume same size
%4517%		CSTMNT[SRCID] = ASGNDATA; ! Change Call node into assgnmnt node
%4517%		CSTMNT[RVRSFLG] = 1;	! Evaluate RHS befor LHS
%4517%		CSTMNT[MEMCMPFLG] = 1;	! No MOVE/MOVEM is needed for asmnt
%4517%
%4517%		!Make a CHAR inlinfn expression node for first arg 
%4517%
%4517%		TMP = .ARGLST[1,ARGNPTR];
%4517%
%4517%		NAME = EXPTAB;	
%4517%		ARGNODE = CSTMNT[LHEXP] = NEWENTRY();	!Make an expression node 
%4517%		ARGNODE[PARENT] = .CSTMNT; 
%4517%		ARGNODE[VALTYPE] = INTEGER;	! INTEGER instead of CHARACTER
%4517%		ARGNODE[OPRCLS] = INLINFN;
%4517%		ARGNODE[OPERSP] = CHARFN;
%4517%		ARGNODE[ARG1PTR] = .TMP;
%4517%		ARGNODE[ARG2PTR] = 0;
%4517%
%4517%		IF .TMP[OPRCLS] EQL DATAOPR
%4517%		THEN ARGNODE[A1VALFLG] = 1
%4517%		ELSE TMP[PARENT] = .ARGNODE;
%4517%
%4522%		IF .TMP[OPRCLS] EQL SUBSTRING
%4522%		OR .TMP[OPRCLS] EQL ARRAYREF
%4522%		OR .TMP[OPR1] EQL VARFL
%4522%		THEN IF NOT ISDUMMY(TMP) 
%4522%		THEN ARGNODE[INCRFLG] = 1;	! INCREMENTED BP
%4517%
%4517%		TMP = .ARGLST[2,ARGNPTR];
%4517%
%4517%		IF .TMP[OPR1] EQL CONSTFL
%4517%		THEN  	! Second arg is a constant
%4517%		BEGIN
%4517%			CSTMNT[RHEXP] = .TMP;
%4517%			CSTMNT[A2VALFLG] = 1;
%4517%			CSTMNT[A2IMMEDFLG] = 1;
%4517%		END
%4517%
%4517%		ELSE 	!Make an inlinfn expression node for second arg 
%4517%		BEGIN
%4517%			NAME = EXPTAB;	
%4517%			ARGNODE = CSTMNT[RHEXP] = NEWENTRY();	!Make an expression node 
%4517%			ARGNODE[PARENT] = .CSTMNT;	
%4517%			ARGNODE[VALTYPE] = INTEGER;	
%4517%			ARGNODE[OPRCLS] = INLINFN;	
%4517%			ARGNODE[OPERSP] = ICHARFN;	
%4517%			ARGNODE[ARG1PTR] = .TMP;	! = .ARGLST[2,ARGNPTR];
%4517%			ARGNODE[ARG2PTR] = 0;	

%4517%			IF .TMP[OPRCLS] EQL DATAOPR
%4517%			THEN ARGNODE[A1VALFLG] = 1
%4517%			ELSE TMP[PARENT] = .ARGNODE;

%4517%			! for non-dummy substrings, arrayrefs and vars
%4517%			! use LDB instead of ILDB
%4522%			IF .TMP[OPRCLS] EQL SUBSTRING
%4522%			OR .TMP[OPRCLS] EQL ARRAYREF
%4522%			OR .TMP[OPR1] EQL VARFL
%4522%			THEN IF NOT ISDUMMY(TMP) 
%4517%			THEN ARGNODE[INCRFLG] = 1;	! INCREMENTED BP	
%4517%		END;
%4517%		RETURN;
%4517%	END;

%2304%	! If the CALL is  really a character concatenation  assignment
%2304%	! (normal  or  statement  function),  call  P2SKFOLD  to  fold
%2304%	! top-level concatenations in the argument list.
%2272%
%2304%	IF .ARGNODE EQL SIXBIT 'CNCAM.' OR .ARGNODE EQL SIXBIT 'CHSFC.'
%2272%	THEN CSTMNT[CALLIST] = P2SKFOLD(.CSTMNT[CALLIST],.CSTMNT);

%2304%	! If the CALL is  really a character  assignment (but not  for
%2304%	! statement functions), call P2SKOVRLP to handle  compile-time
%2304%	! overlap tests.
%2304%
%2304%	IF .ARGNODE EQL SIXBIT 'CASNM.' OR .ARGNODE EQL SIXBIT 'CNCAM.'
%2304%	THEN P2SKOVRLP();

END;	! of SKCALL

GLOBAL ROUTINE FOLDIOLST=
%(***************************************************************************
	ROUTINE TO WALK THRU AN IOLIST FOLDING TOGETHER GROUPS OF ELEMENTS THAT CAN
	BE HANDLED BY A SINGLE CALL TO THE OPERATING SYSTEM ROUTINE IOLST.
	FOLDS TOGETHER BLOCKS OF DATACALL, SLISTCALL, AND ELISTCALL NODES
	SUCH THST:
		1.NO DO-STATEMENT NODES OR CONTINUE-STATEMENT NODES WITH
			DO TERMINATION LABELS OCCUR BETWEEN NODES
		2. FOR AN INPUT STATEMENT, NO ELEMENT IN A BLOCK HAS A VALUE WHICH
			IS DEPENDENT ON AN EARLIER ELEMENT IN THE BLOCK.
	CALLED WITH THE GLOBAL CSTMNT POINTING TO THE STATEMENT WHOSE IOLIST IS TO
	BE FOLDED.
***************************************************************************)%
BEGIN
	REGISTER
		BASE IOLELEM,
		BASE PREVELEM;

	%(***GET PTR TO 1ST ELEM ON IOLIST*****)%
	IOLELEM_.CSTMNT[IOLIST];

	%(***IF THERE IS ONLY ONE ELEMENT ON THE LIST, RETURN***)%
	IF .IOLELEM[CLINK] EQL 0 THEN RETURN;

	%(***TRY TO FORM AN IOLISTCALL NODE FROM THIS ELEMENT TOGETHER WITH THE
		ELEMENT FOLLOWING IT, AND PUT THAT NODE UNDER THE IOLIST FIELD OF
		THE IO STMNT*****)%
	IF .IOLELEM[OPRCLS] EQL IOLSCLS
	THEN
	BEGIN
		IOLELEM_FORMIOLST(.IOLELEM);		!FORMIOLIST RETURNS A PTR TO
							! THE IOLIST FORMED OR (IF
							! UNSUCCESSFUL) A PTR TO IOLELEM
		CSTMNT[IOLIST]_.IOLELEM;
	END
	ELSE
	CIOCALL_-1;


	UNTIL .IOLELEM[CLINK] EQL 0
	DO
	BEGIN
		PREVELEM_.IOLELEM;
		IOLELEM_.IOLELEM[CLINK];
		%(***A STATEMENT NODE ALWAYS CAUSES TERMINATION OF AN IOLIST***)%
		IF .IOLELEM[OPRCLS] EQL STATEMENT
		THEN
		CIOCALL_-1

		ELSE
		IF .IOLELEM[OPRCLS] EQL IOLSCLS
		THEN
		BEGIN
			%(***IF THERE IS NO IOLST CURRENTLY BEING BUILT, SEE 
				WHETHER CAN MEKE ONE OF THIS ELEM AND THE
				ONE FOLLOWING IT
			*******)%
			IF .CIOCALL EQL -1
			THEN
			BEGIN
				IOLELEM_FORMIOLST(.IOLELEM);
				PREVELEM[CLINK]_.IOLELEM;
			END

			ELSE
			%(***ON INPUT, IF THE VALUE OF THIS EXPRESSION IS DEPENDENT
				ON THE CONTENTS OF THE IOLIST BEING FORMED,
				THEN TRY TO START A NEW IOLIST WITH THIS ELEM AND
				THE ONE FOLLOWING IT
			****)%
%2405%			IF (.INPFLAG AND IODEPNDS(.IOLELEM,.CIOCALL))
%2405%				OR CONTFN(.IOLELEM)
			THEN
			BEGIN
				%(***TERMINATE CURRENT IOLIST***)%
				CIOCALL_-1;

				IOLELEM_FORMIOLST(.IOLELEM);
				PREVELEM[CLINK]_.IOLELEM;
			END

			ELSE
			%(***IF THIS ELEMENT CAN BE ADDED TO THE IOLIST BEING
				FORMED, ADD IT***)%
			BEGIN
				%(***REMOVE THIS ELEM FROM THE IOLIST BY LINKING THE
					IOLISTCALL NODE (WHICH DIRECTLY PRECEEDED IT)
					TO THE ELEMENT AFTER IT***)%
				CIOCALL[CLINK]_.IOLELEM[CLINK];

				%(***PUT THIS ELEMENT UNDER THE IOLISTCALL NODE***)%
				CIOCLAST[CLINK]_.IOLELEM;
				IOLELEM[CLINK]_0;
				CIOCLAST_.IOLELEM;

				%(***SET "CURRENT IOLIST ELEMENT" TO BE THE IOLISTCALL NODE***)%
				IOLELEM_.CIOCALL;
			END;

		END;
	END;
END;	! of FOLDIOLST

GLOBAL ROUTINE FORMIOLST(IOLELEM)=
%(***************************************************************************
	ROUTINE TO TRY TO FORM A SINGLE IOLSTCALL NODE
	FROM THE IOLIST ELEMENT "IOLELEM" AND THE IOLIST ELEMENT THAT FOLLOWS
	IT.
	IF THIS ROUTINE IS SUCCESSFUL IN FORMING AN IOLIST, IT
	SETS THE GLOBAL CIOCALL TO POINT TO THE IOLISTCALL NODE CREATED, AND THE
	GLOBAL CIOCLAST TO POINT TO THE "LAST" ELEMENT UNDER THAT LIST (IE THE 2ND
	ELEMENT).
	IF IT WAS UNSUCCESSFUL, IT SETS CIOCALL TO -1
	RETURNS A PTR TO THE NODE FORMED IF SUCCESSFUL, A PTR TO IOLELEM IF NOT.
	IS CALLED WITH THE GLOBAL INPFLAG=TRUE IF THE STMNT INVOLVED IS AN INPUT STMNT.
***************************************************************************)%
BEGIN
	MAP BASE IOLELEM;
	REGISTER
		BASE IOLNODE,
		BASE NXTELEM;

	CIOCALL_-1;
	%(****IF IOLELEM IS THE LAST ELEM ON THE IOLIST, CANNOT DO ANYTHING***)%
	IF .IOLELEM[CLINK] EQL 0 THEN RETURN .IOLELEM;

%1441%

	NXTELEM_.IOLELEM[CLINK];

	%(***IF THE 2ND NODE IS A STMNT, CANNOT FORM AN IOLST***)%
	IF .NXTELEM[OPRCLS] EQL STATEMENT THEN RETURN .IOLELEM;

%1441%	! If the 2nd node contains a function call, cannot form an IOLST
%1441%	IF CONTFN(.NXTELEM) THEN RETURN .IOLELEM;

	%(***FOR INPUT STMNTS, THE VAL OF THE 2ND ARG CANNOT BE
		DEPENDENT ON THE VAL OF THE 1ST ***)%
	IF .INPFLAG
	THEN
	BEGIN
		IF IODEPNDS(.NXTELEM,.IOLELEM) THEN RETURN .IOLELEM;

	END;

	%(***MAKE A NEW NODE - OPRCLS=IOLSCLS, OPERSP=IOLSTCALL****)%

%1530%	NAME<LEFT> = IOLCSIZ;
%1530%	IOLNODE = CORMAN();
%1530%	IOLNODE[OPERATOR] = IOLSTCFL;
%1530%	IOLNODE[IOLSTPTR] = .IOLELEM;
%1530%	IOLNODE[IOLSTATEMENT] = .CSTMNT;	! Pointer to the I/O statement

	%(***SET THE LINK FIELD OF THE NODE CREATED TO PT TO THE ELEM AFTER THE LAST
		ELEM REMOVED FROM TH IOLIST AND PUT UNDER THIS IOLISTCALL***)%
	IOLNODE[CLINK]_.NXTELEM[CLINK];

	%(***SET THE LINK OF THE LAST ELEM UNDER THE IOLSTCALL TO 0***)%
	NXTELEM[CLINK]_0;

	%(***SET UP THE GLOBALS CIOCALL (PTR TO IOLSTCALL NODE BEING FORMED) AND CIOCLAST (PTR
		TO LAST ELEM UNDER CIOCALL) ****)%
	CIOCALL_.IOLNODE;
	CIOCLAST_.NXTELEM;
	RETURN .IOLNODE;
END;	! of FORMIOLST

GLOBAL ROUTINE LOOKELEM2(VARPTR,IOELEM)=
	%(**************************************************************
		ROUTINE TO DETERMINE IF THE VARIABLE VARPTR
		IS USED UNDER ANY EXPRESSION IN THE IOLSCLS
		NODE IOELEM
	**************************************************************)%

BEGIN
	MAP
		BASE VARPTR,
		BASE IOELEM;

	REGISTER BASE IOARRAY;

	ROUTINE FILTER(EXPR,VAR)=
	%(******************************************************

		Routine to FILTER calls to CONTVAR

	******************************************************)%
	BEGIN
		MAP
			BASE EXPR,
			BASE VAR;

%2405%		! The following checks are very dependent on the order
%2405%		! in which they're made.
%2405%
%2405%		! Be less pessimal for SUBSTRINGs
%2405%
%2405%		IF .EXPR[OPRCLS] EQL SUBSTRING
%2405%		THEN
%2405%		BEGIN	! EXPR is a SUBSTRING
%2405%
%2405%			IF CONTVAR(.EXPR[ARG1PTR],.VAR)	! Check upper bound
%2405%			THEN RETURN TRUE;		! Found a dependency
%2405%
%2405%			IF CONTVAR(.EXPR[ARG2PTR],.VAR)	! Check lower bound
%2405%			THEN RETURN TRUE;		! Found a dependency
%2405%
%2405%			! There is no dependency due to the  substring
%2405%			! bounds, so just  use what  we're taking  the
%2405%			! substring from.
%2405%
%2405%			EXPR = .EXPR[ARG4PTR];		! Safe to use name
%2405%
%2405%		END;	! EXPR is a SUBSTRING
%2405%
%2405%		! Ideally we  would return  FALSE  here if  EXPR  were
%2405%		! DATAOPR.  However, other routines  rely on this  not
%2405%		! happening.  For example, LPVARDEPNDS.
%2405%
%2405%		! Be less  pessimal  for  ARRAYREFs,  only  the  index
%2405%		! expression matters.

		IF .EXPR[OPRCLS] EQL ARRAYREF
		THEN IF (EXPR = .EXPR[ARG2PTR]) EQL 0
		THEN RETURN FALSE;

		RETURN CONTVAR(.EXPR,.VAR)

	END;	! of FILTER (local)

	CASE .IOELEM[OPERSP] OF SET

%DATACALL%	RETURN FILTER(.IOELEM[DCALLELEM],.VARPTR);

%SLISTCALL%	RETURN IF FILTER(.IOELEM[SCALLELEM],.VARPTR) THEN 1
			ELSE FILTER(.IOELEM[SCALLCT],.VARPTR);

%IOLSTCALL%	BEGIN
			IOARRAY_.IOELEM[IOLSTPTR];
			WHILE .IOARRAY NEQ 0 DO
			BEGIN
%2405%				IF LOOKELEM2(.VARPTR,.IOARRAY) THEN RETURN 1;
				IOARRAY_.IOARRAY[CLINK]
			END
		END;

%E1LISTCALL%	BEGIN

%1167%			! See if count or incr depends on a previous element

%1167%			IF CONTVAR(.IOELEM[ECNTPTR],.VARPTR) THEN RETURN 1;
%1167%			IF CONTVAR(.IOELEM[E1INCR],.VARPTR) THEN RETURN 1;

			IOARRAY_.IOELEM[ELSTPTR];
			WHILE .IOARRAY NEQ 0 DO
			BEGIN
				IF FILTER(.IOARRAY[E2ARREFPTR],.VARPTR)
				 THEN RETURN 1;
				IOARRAY_.IOARRAY[CLINK]
			END;
!**;[1207], LOOKELEM2, DCE, 3-APR-81
%1207%			IF F77 THEN
%1207%			BEGIN
%1207%				IOARRAY_.IOELEM[ELPFVLCHAIN];
%1207%				WHILE .IOARRAY NEQ 0 DO
%1207%				BEGIN
%1207%					IF FILTER(.IOARRAY[LHEXP],.VARPTR)
%1207%					 THEN RETURN 1;
%1207%					IOARRAY_.IOARRAY[CLINK]
%1207%				END
%1207%			END
		END; ! Of E1LISTCALL

%E2LISTCALL%	BEGIN

%1167%			! See if count depends on a previous element

%1167%			IF CONTVAR(.IOELEM[ECNTPTR],.VARPTR) THEN RETURN 1;

			IOARRAY_.IOELEM[ELSTPTR];
			WHILE .IOARRAY NEQ 0 DO
			BEGIN
				IF FILTER(.IOARRAY[E2ARREFPTR],.VARPTR)
				THEN RETURN 1;

%1167%				! See if incr depends on a previous element

%1167%				IF CONTVAR(.IOARRAY[E2INCR],.VARPTR)
				THEN RETURN 1;

				IOARRAY_.IOARRAY[CLINK]
			END;
!**;[1207], LOOKELEM2, DCE, 3-APR-81
%1207%			IF F77 THEN
%1207%			BEGIN
%1207%				IOARRAY_.IOELEM[ELPFVLCHAIN];
%1207%				WHILE .IOARRAY NEQ 0 DO
%1207%				BEGIN
%1207%					IF FILTER(.IOARRAY[LHEXP],.VARPTR)
%1207%					 THEN RETURN 1;
%1207%					IOARRAY_.IOARRAY[CLINK]
%1207%				END
%1207%			END
		END; ! Of E2LISTCALL
	TES;
	RETURN 0
END; ! of LOOKELEM2

GLOBAL ROUTINE IODEPNDS(IOELEM2,IOELEM1)=
%(***************************************************************************
	ROUTINE TO DETERMINE WHETHER THE IOLIST ELEMENT IOELEM2 HAS A VALUE
	WHICH IS DEPENDENT ON THE EVALUATION OF IOLELEM1.
	THIS ROUTINE IS ONLY CALLED FOR INPUT IOLISTS - HENCE IT CAN
	BE ASSUMED THAT THE ELEMENT UNDER A DATACALL CAN ONLY BE A
	VARIABLE OR ARRAYREF.
	THIS ROUTINE IS ONLY CALLED FOR BOTH IOLELEM1 AND IOLELEM2 WITH
	OPRCLS=IOLSCLS
***************************************************************************)%
BEGIN
	MAP
		BASE IOELEM1,
		BASE IOELEM2;

	REGISTER BASE IOARRAY;

%(***	THIS ROUTINE IS DRIVEN BY LOOKING AT THE ELEMENT TO
	BE APPENDED TO.

	FOR EACH VARIABLE "READ" BY THAT ELEMENT A CALL
	IS MADE TO LOOKELEM2 TO SEE IF THE
	SECOND ELEMENT USES THAT VARIABLE IN ANY
	COMPUTATION.

	IF SO, THE IONODES ARE DEPENDENT, IF NOT, INDEPENDENT.

***)%

	CASE .IOELEM1[OPERSP] OF SET

%DATACALL%	RETURN LOOKELEM2(.IOELEM1[DCALLELEM],.IOELEM2);

%SLISTCALL%	RETURN LOOKELEM2(.IOELEM1[SCALLELEM],.IOELEM2);

%IOLSTCALL%	BEGIN
			IOARRAY_.IOELEM1[IOLSTPTR];
			WHILE .IOARRAY NEQ 0 DO
			BEGIN
				IF IODEPNDS(.IOELEM2,.IOARRAY) THEN RETURN 1;
				IOARRAY_.IOARRAY[CLINK]
			END
		END;

%E1LISTCALL%	BEGIN
			IOARRAY_.IOELEM1[ELSTPTR];
			WHILE .IOARRAY NEQ 0 DO
			BEGIN
				IF LOOKELEM2(.IOARRAY[E2ARREFPTR],.IOELEM2)
				 THEN RETURN 1;
				IOARRAY_.IOARRAY[CLINK]
			END;
!**;[1207], IODEPNDS, DCE, 3-APR-81
%1207%			IOARRAY_.IOELEM1[ELPFVLCHAIN];
%1207%			WHILE .IOARRAY NEQ 0 DO
%1207%			BEGIN
%1207%				IF LOOKELEM2(.IOARRAY[LHEXP],.IOELEM2)
%1207%				 THEN RETURN 1;
%1207%				IOARRAY_.IOARRAY[CLINK]
%1207%			END
		END;

%E2LISTCALL%	BEGIN
			IOARRAY_.IOELEM1[ELSTPTR];
			WHILE .IOARRAY NEQ 0 DO
			BEGIN
				IF LOOKELEM2(.IOARRAY[E2ARREFPTR],.IOELEM2)
				 THEN RETURN 1;
				IOARRAY_.IOARRAY[CLINK]
			END;
!**;[1207], IODEPNDS, DCE, 3-APR-81
%1207%			IOARRAY_.IOELEM1[ELPFVLCHAIN];
%1207%			WHILE .IOARRAY NEQ 0 DO
%1207%			BEGIN
%1207%				IF LOOKELEM2(.IOARRAY[LHEXP],.IOELEM2)
%1207%				 THEN RETURN 1;
%1207%				IOARRAY_.IOARRAY[CLINK]
%1207%			END
		END;
	TES;
RETURN 0
END;	! of IODEPNDS

GLOBAL ROUTINE LPVARDEPNDS(IOELEM2,IOELEM1)=
%(***************************************************************************
	This routine determines whether there is any dependency between
	a loop variable which might occur in IOELEM1 and any variable
	occurring in IOLIST IOELEM2.  This is used only for output
	statements where loop variables may take on new (final) values.
	In an output list, new values can be generated only by loop
	variables and druing function calls (which are handled in COLLAPSE).
	For example, WRITE() (A(I),I=1,10),I represents a dependency which
	should cause separate .IOLST calls - the dependency is caught here.
	This entire routine was added by edit 1207.
***************************************************************************)%
BEGIN
	MAP
		BASE IOELEM1,
		BASE IOELEM2;
	REGISTER BASE IOARRAY;

	CASE .IOELEM1[OPERSP] OF SET

%DATACALL%	RETURN 0;	! No loop variables in a DATACALL node

%SLISTCALL%	RETURN 0;	! No loop variables in an SLISTCALL node

%IOLSTCALL%	BEGIN
			IOARRAY_.IOELEM1[IOLSTPTR];
			WHILE .IOARRAY NEQ 0 DO
			BEGIN
				IF LPVARDEPNDS(.IOELEM2,.IOARRAY)
				 THEN RETURN 1;
				IOARRAY_.IOARRAY[CLINK]
			END
		END;

%E1LISTCALL%	BEGIN
			IOARRAY_.IOELEM1[ELPFVLCHAIN];
			WHILE .IOARRAY NEQ 0 DO
			BEGIN
				IF LOOKELEM2(.IOARRAY[LHEXP],.IOELEM2)
				 THEN RETURN 1;
				IOARRAY_.IOARRAY[CLINK]
			END
		END;
				
%E2LISTCALL%	BEGIN
			IOARRAY_.IOELEM1[ELPFVLCHAIN];
			WHILE .IOARRAY NEQ 0 DO
			BEGIN
				IF LOOKELEM2(.IOARRAY[LHEXP],.IOELEM2)
				 THEN RETURN 1;
				IOARRAY_.IOARRAY[CLINK]
			END
		END;
	TES;

	RETURN 0 ! => No dependency.

END; ! of LPVARDEPNDS

GLOBAL ROUTINE DOP2SKL=
BEGIN
	! Routine to handle p2skeleton functions for do statements

	REGISTER BASE DOEXPR;

	!INITIALIZE NEGFLG AND NOTFLG TO FALSE
	NEGFLG_FALSE;
	NOTFLG_FALSE;

	DOEXPR_.CSTMNT[DOLPCTL];

	! Call the dispatch for the DO loop control

	IF .DOEXPR[OPRCLS] NEQ DATAOPR THEN
		CSTMNT[DOLPCTL] = (.P2SKL1DISP[.DOEXPR[OPRCLS]])(.DOEXPR);

	! Set  up   (if  necessary)   for  the   leaf  substitution   of
	! reg-contents nodes for the do induction variable.

	! To insure  optimal  usage  of  the  induction  variable  in  a
	! register on an  innermost do  loop the global  CDONODE will  point
	! back to the DO  statement so that flags  can be set and  unset
	! properly.   (???change  for  large  source  solution???)   The
	! global DOWDP will have the "DOISUBS"  bit set to 0 whenever  a
	! condition is  detected which  necessitates materialization  of
	! both loop index and count; the "DONOAOBJN" bit set whenever  a
	! condition is detected which prevents use of "AOBJN" loop;  the
	! "DOMTRLZIX" bit set whenever a condition is encountered  which
	! necessitates materialization of the loop index only.

	IF .CSTMNT[INNERDOFLG] THEN
	BEGIN	! This DO loop is an innermost DO

		INNERLOOP_TRUE;	!SET GLOBAL FLAG FOR "PROCESSING STMNTS
				! IN AN INNERMOST LOOP"
		DOWDP_0;
		CDONODE_.CSTMNT;
		DOWDP[DOINDUC]_.CSTMNT[DOSYM];
		CSTMNT[NEDSMATRLZ]_0;
		DOWDP[DOISUBS]_1;
		DOWDP[DONOAOBJN]_0;
		DOWDP[DOMTRLZIX]_0;
		TRANSFOUT_FALSE;

		!KEEP A TABLE OF LABELS THAT OCCUR WITHIN THIS
		! LOOP. ALSO KEEP A COUNT OF THE NUMBER OF REFERENCES
		! TO EACH SUCH LABEL THAT OCCUR FROM WITHIN THE
		! LOOP.
		!IF A TRANSFER OUT OF THE LOOP (IE A TRANSFER TO A LABEL
		! NOT IN THE TABLE) IS DETECTED, THE LOOP INDEX MUST BE
		! MATERIALIZED. IF A TRANSFER INTO THE LOOP IS DETECTED
		! (IE THE REF CT FOR A LABEL IS GTR THAN THE NUMBER OF
		! REFS FROM WITHIN THE LOOP), THEN IF THERE ARE ANY TRANSFERS
		! OUT, AN EXTENDED RANGE IS ASSUMED AND THE
		! COUNT-CTL VAR MUST BE MATERIALIZED AS WELL AS THE INDEX.
		! IF THERE IS TRANSFER IN BUT NO TRANSFER OUT, HAVE AN ERROR

		CTR_1;
		CHOSEN[0,LABL]_.CDONODE[DOLBL];	!PUT THE LOOP TERMINATING LABEL
						! INTO THE TABLE

		CHOSEN[0,LOCREFCT]_0;	!IN COUNTING REFS WE WILL NOT CT REFS
					! AS LOOP ENDINGS

		DOEXPR_.CDONODE[SRCLINK];
		WHILE .DOEXPR[SRCLBL] NEQ .CDONODE[DOLBL] DO	!LOOK AT ALL STMNTS IN THE LOOP
		BEGIN
			IF .DOEXPR[SRCLBL] NEQ 0 THEN
			BEGIN
				CHOSEN[.CTR,LABL]_.DOEXPR[SRCLBL];
				CHOSEN[.CTR,LOCREFCT]_0;	!INIT REF CT
				CTR_.CTR+1;
				IF .CTR GEQ 32 THEN
				BEGIN
					!CHOSEN IS FULL. FORGET IT.
					DOWDP[DOISUBS]_0;
					CDONODE[NEDSMATRLZ]_1;
					RETURN;
				END;
			END;
			DOEXPR_.DOEXPR[SRCLINK];
		END;
	END;	! This DO loop is an innermost DO

END;	! of DOP2SKL

ROUTINE TRINTOLOOP=
%(***************************************************************************
	ROUTINE TO EXAMINE THE CONTENTS OF THE TABLE "CHOSEN" TO DETERMINE
	WHETHER THERE ARE ANY TRANSFERS INTO THE DO LOOP
	WHICH HAS JUST BEEN PROCESSED.
	THE "LOCREFCT" FIELD OF THE ENTRY FOR EACH LABEL CONTAINS A CT
	OF THE NUMBER OF TRANSFERS TO THIS LABEL THAT OCCUR
	WITHIN THE LOOP.
***************************************************************************)%
BEGIN
	REGISTER PEXPRNODE LABENTRY;

	INCR I FROM 0 TO (.CTR-1)	!LOOK AT EACH ENTRY IN THE TABLE
	DO
	BEGIN
		LABENTRY_.CHOSEN[.I,LABL];
		IF (.LABENTRY[SNREFNO]	!NUMBER OF REFS TO THIS LABEL
					! OTHER THAN AS A FORMAT
		    -1			! DONT COUNT THE DEFINITION OF THE LABEL
		    -.LABENTRY[SNDOLVL]) ! DONT COUNT REFERENCES TO THE LABEL
					! THAT WERE REFERENCES AS DO LOOP TERMINATIONS
		   GTR .CHOSEN[.I,LOCREFCT]	!IF THE NUMBER OF REFS FROM INSIDE
					! THE LOOP WAS LESS THAN THE TOTAL REFERENCES
		THEN RETURN TRUE;	!THEN THERE MUST BE A TRANSFER INTO
					! THE RANGE OF THE LOOP
	END;

	RETURN FALSE;	!IF NO LABELS HAVE LOCAL CTS THAT ARE LESS THAN
			! THEIR TOTAL CTS - THEN NO TRANSFERS INTO THE LOOP
END;	! of TRINTOLOOP

GLOBAL ROUTINE DOENSKL=
%(***************************************************************************
	ROUTINE TO DO P2SKEL PROCESSING FOR THE TERMINATION OF AN INNERMOST
	DO LOOP.
	THIS ROUTINE IS CALLED WITH THE GLOBAL "CSTMNT" POINTING TO A STATEMENT
	THAT HAS A LABEL. IT IS ONLY CALLED IF THE GLOBAL "INNERLOOP"
	IS "TRUE" (INDICWTING THAT WE ARE PROCESSING AN INNER DO LOOP).
	IT CHECKS WHETHER THE LABEL ON THIS STMNT ENDS THE
	CURRENT DO LOOP.
	AT THE END OF AN INNER DO LOOP, IT DETERMINES WHETHER 
		1. THE LOOP INDUCTION VARIABLE AND THE LOOP CT MUST
			BOTH BE MATERIALIZED (IN WHICH CASE "NEDSMATRLZ"
			GETS SET IN THE DO STMNT)
			
		2. THE LOOP CT CAN STAY IN A REG, BUT THE INDUCTION
			VARIABLE MUST BE MATERIALIZED (IN WHICH CASE "MATRLZIXONLY"
			IS SET IN THE DO STMNT)
		3. "AOBJN" SHOULD NEVER BE USED FOR THIS LOOP
			("NOFLCWDREG" SET IN THE DO STMNT)
***************************************************************************)%
BEGIN
	REGISTER BASE DOVAR;	!TO CHECK SYMBOL FOR BEING IN COMMON
				!AND/OR EQUIVALENCED

	%(***IF ARE AT THE TERMINATION LABEL OF THE DO LOOP WHOSE STMNT
		NODE WAS THE LAST DO STMNT SEEN (HENCE ARE AT THE TERMINATION
		OF AN INNERMOST-LOOP)****)%
	IF .CSTMNT[SRCLBL] EQL .CDONODE[DOLBL]

	THEN
	BEGIN
		%(***CHECK WHETHER THERE ARE ANY TRANSFERS IN TO THIS
			LOOP***)%
		IF TRINTOLOOP()
		THEN
		BEGIN
			%(***IF THERE ARE BOTH TRANSFERS IN AND TRANSFERS OUT,
				ASSUME AN EXTENDED RANGE AND MATERIALIZE BOTH
				THE LOOP CT AND THE INDUCTION VARIABLE**)%
			IF .TRANSFOUT
			THEN
			CDONODE[NEDSMATRLZ]_1

			ELSE
			%(***IF THERE ARE TRANSFERS OUT BUT NO TRANSFERS IN,
				GIVE AN ERROR MESSAGE***)%
			BEGIN
				CDONODE[NEDSMATRLZ]_1;
			END;
		END

		ELSE
		%(***IF THE FLAG "DOISUBS" HAS BEEN TURNED OFF WHILE PROCESSING
			THE STATEMENTS IN THIS LOOP, MUST SET "NEDSMATRLZ" FLAG
			ON THE DO-LOOP NODE.***)%
		IF NOT .DOWDP[DOISUBS]
		THEN CDONODE[NEDSMATRLZ]_1

		ELSE
		%(***IF THE FLAG "DOMTRLZIX" HAS BEEN SET, MUST SET
			THE "MATRLZIXONLY" FLAG IN THE DO STMNT.
			ALSO, IF THE DO LOOP INDEX IS IN COMMON
			OR EQUIVALENCED IN MUST BE MATERIALIZED***)%
		BEGIN
			DOVAR_.CDONODE[DOSYM];
			IF .DOWDP[DOMTRLZIX]
			OR .DOVAR[IDATTRIBUT(INCOM)]
			OR .DOVAR[IDATTRIBUT(INEQV)]
			OR (.FLGREG<DBGINDX>	!IF /DEB:INDEX WAS SPECIFIED BY THE USER
				AND NOT .FLGREG<OPTIMIZE>)
			THEN
				CDONODE[MATRLZIXONLY]_1;
		END;


		%(***IF THE FLAG "DONOAOBJN" HAS BEEN SET WHILE PROCESSING
			THE STATEMENTS IN THIS LOOP, MUST UNDO THE DETERMINATION
			THAT THIS LOOP BE HANDLED WITH AN AOBJN***)%
		IF .DOWDP[DONOAOBJN]
		THEN
		BEGIN
			CDONODE[NOFLCWDREG]_1;	!SET FLAG SO THAT THE OPTIMIZER WONT LATER
						! DECIDE TO HAVE THE LOOP BE HANDLED
						! BY AN AOBJN THAT LIVES IN A REG

			IF .CDONODE[FLCWD]
			THEN UNFLDO(.CDONODE);
		END;

		INNERLOOP_FALSE;	!AFTER THIS STMNT WILL NO LONGER
					! BE IN AN INNERMOST LOOP

	END;
END;	! of DOENSKL

GLOBAL ROUTINE P2REGCNTS=
%(***************************************************************************
	THIS ROUTINE IS CALLED FOR EACH STATEMENT IN AN INNERMOST DO LOOP TO
	DETERMINE WHETHER ANY CONDITIONS EXIST WHICH PREVENT THE LOOP INDEX
	FROM BEING KEPT IN A REGISTER.
	THE THINGS THAT PREVENT THIS ARE:
		1.TRANSFER OUT OF LOOP
		2.A NON-LIBRARY FUNCTION REFERENCE WITH
		  LOOP INDEX IN COMMON
		3. A FN REFERENCE WITH LP INDEX AS A PARAMETER
		4. A CALL STMNT (THIS ALSO PREVENTS THE CTL-COUNT
			VAR FROM BEING KEPT IN A REG)
	IF CONDITION 1,2, OR 3 IS DETECTED, THE FLAG "DOMTRLZIX" IS
	SET IN THE GLOBAL VARIABLE "DOWDP".
	IF CONDITION 4 IS DETECTED, THE BIT "DOISUBS" IS SET TO 0.

***************************************************************************)%
BEGIN
	MACRO QUIT=
	BEGIN
		DOWDP[DOISUBS]_0;
		CDONODE[NEDSMATRLZ]_1;
	END$;

	REGISTER
		LBLPTR,
		BASE ARGNOD;

	IF NOT .DOWDP[DOISUBS] THEN RETURN;

	IF .CSTMNT[USRFNREF] 	!IF THIS STMNT REFERENCES A USER FN
	THEN			! THEN IF THE LP INDUCTION VAR IS IN COMMON
				! IT MUST BE MATERIALIZED
	BEGIN
		ARGNOD_.CDONODE[DOSYM];
		IF .ARGNOD[IDATTRIBUT(INCOM)] THEN
		DOWDP[DOMTRLZIX]_1
	END;


	%(***ACTION TO BE TAKEN DEPENDS ON SRCID OF STMNT**)%
	CASE .CSTMNT[SRCID] OF SET

	BEGIN END;	! ASSIGNMENT
	BEGIN END;	! ASSIGN STATEMENT
	QUIT;		! CALL
	BEGIN END;	! CONTINUE
	BEGIN END;	! DOID
	BEGIN END;	! ENTRID
	BEGIN END;	! COMMONSUB
	LOOKOUT(.CSTMNT[GOTOLBL]);	! GOTO

	BEGIN		! AGOTO
		IF .CSTMNT[GOTOLIST] EQL 0
		THEN QUIT
		ELSE DECR I FROM .CSTMNT[GOTONUM]-1 TO 0 DO
		BEGIN
			LBLPTR_@(.CSTMNT[GOTOLIST]+.I);
			LOOKOUT(.LBLPTR);
		END;
	END;		! AGOTO

	BEGIN		! CGOTO
		DECR I FROM .CSTMNT[GOTONUM]-1 TO 0 DO
		BEGIN
			LBLPTR_@(.CSTMNT[GOTOLIST]+.I);
			LOOKOUT(.LBLPTR);
		END;
	END;		! CGOTO

	BEGIN		! ARITHMETIC IF
		LOOKOUT(.CSTMNT[AIFLESS]);
		LOOKOUT(.CSTMNT[AIFEQL]);
		LOOKOUT(.CSTMNT[AIFGTR]);
	END;		! ARITHMETIC IF

	BEGIN END;	! LOGICAL IF (P2REGCNTS WILL BE CALLED FROM SKSTMN
			! FOR THE SUBSTATEMENT)
	QUIT;		! RETURN
	BEGIN END;	! STOP
%1742%	LOKIOUT();	! READ
%1742%	LOKIOUT();	! WRITE
%1742%	LOKIOUT();	! DECODE
%1742%	LOKIOUT();	! ENCODE
%1742%	LOKIOUT();	! REREAD
%1742%	LOKIOUT();	! FIND
%1742%	LOKIOUT();	! CLOSE
%4502%	LOKIOUT();	! DELETE
%4503%	LOKIOUT();	! REWRITE
%1742%	LOKIOUT();	! BACKSPACE
%1742%	LOKIOUT();	! BACKFILE
%1742%	LOKIOUT();	! REWIND
%1742%	LOKIOUT();	! SKIPFILE
%1742%	LOKIOUT();	! SKIPRECORD
%1742%	LOKIOUT();	! UNLOAD
%4504%	LOKIOUT();	! UNLOCK
%1742%	LOKIOUT();	! ENDFILE
%1742%	BEGIN END;	! END
%1742%	BEGIN END;	! PAUSE
%1742%	LOKIOUT();	! OPEN
%1742%	BEGIN END;	! SFN
%1742%	BEGIN END;	! FORMAT
%1742%	BEGIN END;	! BLT (not implemented)
%1742%	BEGIN END;	! REGMASK (not implemented)
%2200%	LOKIOUT();	! INQUIRE

	TES;
END;	! of P2REGCNTS

ROUTINE LOOKOUT(LABLE)=
%(***************************************************************************
	ROUTINE TO CHECK WHETHER THE LABEL "LABLE" IS IN THE TABLE
	OF LABELS THAT OCCUR INSIDE THE INNERMOST DO LOOP CURRENTLY BEING
	PROCESSED. IF THE COUNT OF LOCAL REFERENCES TO
	THAT LABEL IS INCREMENTED. IF IT IS NOT, THEN
	THE FLAG "DOMTRLZIX" GETS SET INDICATING THAT THIS
	LOOP MUST HAVE ITS INDEX MATERIALIZED SINCE IT CONTAINS
	A TRANSFER OUT
***************************************************************************)%
BEGIN
	!SEARCH THE VECTOR CHOSEN FOR THE LABEL
	!LABLE.
	INCR I FROM 0 TO (.CTR-1) DO
	BEGIN
		IF .CHOSEN[.I,LABL] EQL .LABLE THEN
		BEGIN
			CHOSEN[.I,LOCREFCT]_.CHOSEN[.I,LOCREFCT]+1;
			RETURN
		END;
	END;

	%(***IF COULDNT FIND THE LABEL**)%
	TRANSFOUT_TRUE;
	DOWDP[DOMTRLZIX]_1;
END;	! of LOOKOUT

ROUTINE LOKIOUT=
!CSTMNT PTS TO AN I/O STMNT. LOOK AT IOEND AND IOERR TO SEE IF THEY ARE
! OUTSIDE THE CURRENT DO LOOP
BEGIN
	IF .CSTMNT[IOEND] NEQ 0 THEN LOOKOUT(.CSTMNT[IOEND]);
	IF .CSTMNT[IOERR] NEQ 0 THEN LOOKOUT(.CSTMNT[IOERR]);
END;	! of LOKIOUT

GLOBAL ROUTINE ARNOAOBJN(ARRREF)=	![2243] New

!++
! FUNCTIONAL DESCRIPTION:
!
!	Determines for a numeric array reference if:
!
! 		o the array is in PSLARGE,
!	 	o and in an innermost DO loop,
!	 	o and the index variable for an innermost AOBJN DO  loop
!		  is in the address calculation for the array.
!
!	If all are true, then it marks that the innermost DO should  not
!	be an AOBJN loop by setting the field DONOAOBJN in DOWDP.
!
! FORMAL PARAMETERS:
!
!	ARRREF		Is the array reference to check.
!
! IMPLICIT INPUTS:
!
!	DOWDP		Keeps information on innermost DO loop
!
!	INNERLOOP	Flag  is  TRUE  when  processing  stmts  in   an
!			innermost DO
!
! IMPLICIT OUTPUTS:
!
!	DOWDP		Keeps information on innermost DO loop
!
! ROUTINE VALUE:
!
!	None
!
! SIDE EFFECTS:
!
!	None
!
!--


BEGIN
	MAP BASE ARRREF;

	REGISTER
		BASE ADDRCALC,	! Address calculation for the array
		BASE SYMTAB;	! Symbol table reference for the array


	! If for some  reason this routine  does not catch  a case  (for
	! instance,  EQUIVALENCE  processing  is  done  much  later   in
	! compilation), the back  end will  copy the right  half of  the
	! index register into another register,  unless this DO loop  is
	! made no-AOBJN by someplace else.  Making the loop no-AOBJN  is
	! more optimal, in  terms of  code generated,  than copying  the
	! right hand half of the register.


	IF .INNERLOOP				! In innermost DO
	THEN IF NOT .DOWDP[DONOAOBJN]		! Has someone already done?
	THEN IF .ARRREF[VALTYPE] NEQ CHARACTER	! Numeric array only
	THEN
	BEGIN	! In innermost DO loop

		SYMTAB = .ARRREF[ARG1PTR];		! Array STE

		IF .SYMTAB[IDPSECT] EQL PSLARGE	! In PSLARGE?
		THEN
		BEGIN	! In .LARG.

			! Check if DO index is in address calc.  We will look
			! for the address calculation expression being either
			! "I" or "constant+I" (where "I" is the loop index).
			! DOWDP[DOINDUC] points to the innermost DO loop's
			! index variable.

			ADDRCALC = .ARRREF[ARG2PTR];	! Array's addr calc

			IF .ADDRCALC EQL .DOWDP[DOINDUC]	! "I"?
			THEN DOWDP[DONOAOBJN] = 1		! Yes, no AOBJN
			ELSE
			BEGIN	! Not "I"

				! Check for the form "constant+I".  This is all
				! we need to check, since the expression in
				! canonical.

				IF .ADDRCALC[OPR1] EQL ADDOPF	  ! "+"
				THEN IF .ADDRCALC[ARG2PTR] EQL .DOWDP[DOINDUC]
				THEN
				BEGIN	! "something+I".

					! If the something is a constant then
					! this is "constant+I".  The constant
					! will eventually be hidden in the Y
					! field of the EFIW used to reference
					! the array, and the index register
					! containing the loop induction
					! variable will be part of the EFIW.
					! Since we will have to worry about the
					! negative left half of the AOBJN
					! counter sometime, we might as well
					! worry about it now.

					ADDRCALC = .ADDRCALC[ARG1PTR];

					IF .ADDRCALC[OPR1] EQL CONSTFL
					THEN DOWDP[DONOAOBJN] = 1; ! No AOBJN

				END;	! "something+I".

			END;	! Not "I"

		END;	! In .LARG.

	END;	! In innermost DO loop

END;	! of ARNOAOBJN

! Below is for use in making PLM's with RUNOFF
!++
!.END LITERAL
!--

END
ELUDOM