Google
 

Trailing-Edge - PDP-10 Archives - BB-D480F-BB_1985_short - cgdo.bli
There are 12 other files named cgdo.bli in the archive. Click here to see a list.
!COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1972, 1985
!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 NORMA ABEL/HPW/MD/DCE/SJW/RDH/TFV/CKS/AHM/CDM/RVM/TJK

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

GLOBAL BIND CGDOV = #10^24 + 0^18 + #2462;	! Version Date:	2-Oct-84


%(

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

119	-----	-----	MAKE ARGGEN A GLOBAL ROUTINE

120	-----	-----	IN "CGRETURN", WHEN LOOK FOR NEXT STMNT AFTER
			THE RETURN EQUAL TO END, SKIP OVER AN INTERVENING CONTINUE
121	-----	-----	IN "CGRETURN", WHEN CHECKING THE SRCID OF NXTSTMNT,
			MUST FIRST CHECK THE NXTSTMNT NEQ 0
122	-----	-----	IN "CGRETURN", GENERATE A RETURN WHEN THERE
			ARE LABEL ARGUMENTS IN ALL CASES
123	-----	-----	FIX ARGGEN TO PERMIT MULTIPLE LEVEL PASSING
			OF SUBPROGRAM NAMES
124	-----	-----	FIX 123 (I HOPE)
125	-----	-----	CHANGE REFERENCES TO PROEPITYP
126	-----	-----	PUT OUT TYPE CODE WITH LABEL ARGUMENTS
127	-----	-----	GIVE ERROR MESSAGES FOR MULTIPLE RETURN
					WHEN THERE WERE NO LABEL PARAMS; AND
			FOR VALUE OF A FN NEVER DEFINED
128	-----	-----	MESSAGE FOR VAL OF FN UNDEFINED SHOULD NOT
			BE GIVEN FOR A STMNT FN
129	-----	-----	MACRO SET1ZGEN MISSPELLED IN CGRETURN
130	-----	-----	FIX CALLS TO FATLERR TO INCLUDE .ISN
131	-----	-----	WHEN /DEB:TRACE WAS SPECIFIED, FOR STMNT FNS
			AND ENTRIES THE XCT FDDT. MUST BE GENERATED AFTER
			THE ENTRY NAME IS DEFINED.
132	-----	-----	IN "CGPROEPI", SHOULD CLEAR PBFISN FIELD
			BEFORE OUTPUT SIXBIT FOR ENTRY NAME; SET
			IT TO THE STMNT ISN BEFORE THE 1ST INSTRUCTION
133	-----	-----	GENERATE COMMON SUBS ON DO STMNTS
134	256	15493	DO NOT LOOK FOR LABEL DUMMIES IN STATEMENT FUNCTIONS,
			(JNT)
135	323	16729	USE .A00NN FOR NAME OF TEMPORARY USED  TO SAVE
			REGISTERS IN PROLOGUE OF A FUNCTION, (MD)
136	360	18243	FIX RETURN BEFORE CONTINUE, END STMNTS, (DCE)

***** Begin Version 5A *****

137	607	22685	SET GLOBAL FLAG NEDZER IN CGSBPRGM TO INDICATE
			  ZERO-ARG-BLOCK NEEDED
140	613	QA2114	IGNORE INDIRECT BIT IN FORMAL FUNCTION TARGET
			  ON ENTRY PROLOGUE, (SJW)

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

141	674	11803	TEST FOR DOSTAK OVERFLOW AND GIVE ERROR MSG, (DCE)
142	677	25573	GENERATE CODE TO CHECK FOR CORRECT
			 NUMBER OF PARAMETERS IF DEBUG:PARAM SET, (DCE)

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

143	750	TFV	1-Jan-80	------
	remove Debug:parameters (edit 677)

144	761	TFV	1-Mar-80	-----
	Remove KA10FLG and add in /GFLOATING

145	1002	TFV	1-Jul-80	------
	MAP EVALU onto EVALTAB to get the argtype for argblock entries

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

146	1206	DCE	20-Mar-81	-----
	For real DO loops, put out potential jump around (zero trip F77)
	together with a label for it, and be sure to make "final" loop value
	available at end of loop.

147	1227	CKS	22-Jun-81
	Use CONST2L instead of CW4L to access LH of constant AOBJN pointer.

148	1253	CKS	11-Aug-81
	When ARGGEN is doing a character arrayref node, point symbol table
	pointer at the .Q temp (from TARGADDR) not the array name
	(from ARG1PTR).

149	1266	TFV	5-Oct-81	------
	Add code to copy 1 or 2 words of descriptor for character formal
	at subroutine entrance.  Don't copy it back on subroutine exit.
	Fix up lots of code and comments to look nice.

150	1276	DCE	21-Oct-81	-----
	Only materialize loop variable at normal exit if /F77 given.

151	1400	CKS	21-Oct-81
	In CGSBPRGM, check for function call with zero arguments and use ZERBLK

152	1401	AHM	2-Oct-81
	Make ARGGEN emit arg block entries that are IFIWs.  Do the  same
	in CGPROEPI  for  the vector  of  addresses that  point  into  a
	subroutine's arg  block used  for  multiple returns.   Delete  a
	macro that  fudged over  misspellings  of ENTLIST  in  CGPROEPI.
	Rework and pretty up ARGGEN and CGARGS.  Put form feeds  between
	all routines in this module.

153	1422	TFV	12-Nov-81	------
	Fix CGEPILOGUE  to handle  character functions.   The result  of
	character functions is  not returned in  AC0, AC1.  Instead  the
	first argument has the descriptor for the result.

154	1437	CDM	16-Dec-81	------
	Save address call in CGARGS to a subprogram for argument checking
	processing.

155	1455	TFV	5-Jan-82	------
	Modify CGSFN  for  character statement  function.   A  statement
	function is turned into either a call to CHSFN.  (the subroutine
	form of CHASN.)  or  a call to CHSFC.   (the subroutine form  of
	CONCA.).  CHSFC.   is  used  if  the  character  expression  has
	concatenations at its top  level, CHSFN. is  used for all  other
	character expressions.  Modify  CGSBPRGM so it  doesn't set  the
	indirect bit for character statement function names.

156	1466	CDM	2-Feb-82
	Modified CGARGS to allow zero argument blocks to be allocated if
	/DEBUG:ARGUMENTS is specified.

1505	AHM	9-Mar-82
	Set the IDPSECT field in symbol table enties for .A00nn  temps
	to .DATA.  Also optimize macro TNAME by removing a LSH and two
	adds.

1524	RVM	31-Mar-82
	Don't turn on the indirect bit of an argument block entry for
	an argument of type dummy character function.

1526	AHM	27-Apr-82
	Don't subtract HIORIGIN from  the address of subroutine  calls
	when saving them for argument checking in CGARGS, since we now
	never add it in in the first place.

1533	TFV	17-May-82
	Modify CGSBPRGM for dynamic concatenations.  Call CHMRK.  before
	the subprogram  call  and  call  CHUNW.  after.   If  there  are
	multiple returns, generate error handling code to do the  CHUNW.
	call and then JRST to the user label.

1562	TFV	18-Jun-82
	Fix CGSBPRGM to only check ARGMARK if there is an argument list.

1613	CDM	13-Aug-82
	Change /DEBUG:PARAMETERS to /DEBUG:ARGUMENTS.


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

2245	CDM	18-Dec-83
	Improve argument checking.  Subroutine  calls with no  arguments
	would not output  argument checking (1120)  rel blocks for  Link
	unless /DEBUG:ARGUMENTS was  given.  Now always  output the  the
	rel block, and change the call to the subroutine not to have its
	own unique  argument block  of  0, but  instead use  the  shared
	ZERBLK which  everyone  else  with no  arguments  shares.   This
	simplifies code in several places.
	Delete unneeded local variable ARGFLG in CGSBPRGM.  Code becomes
	much simpler without it.

2313	TJK	21-Feb-84
	Rewrite CGRETURN.   This  routine  had a  number  of  problems
	including inefficiency  within the  routine itself,  incorrect
	code produced for  alternate returns  using array  references,
	and pessimal code  produced for some  cases.  Added a  routine
	header.  Removed macro  MOV1GEN.  Commented  out code  pattern
	MOVRET.  Added entry point for code pattern OPGZER.

2317	AHM	4-Mar-84
	Make ARGGEN use GENREF to construct memory references instead
	of doing it itself.  Remove code in CGPROEPI which believed
	that formal array STEs had an indirect bit set in IDADDR.

2462	AHM	2-Oct-84
	Use execrable TRUE/FALSE/TRUTH/FALSITY miasma for boolean in
	call to GENREF to satisfy programming conventions.

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

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

)%

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

! Below is for RUNOFF in generating .PLM files
!++
!.LITERAL
!--

OWN
	JUMPABOUT,
	JMPVECT,
	LABARGCT,
	JMPSFN,
%1505%	BASE EPILAB;	! Holds pointer to labels  of epilogue code  and
			! STE of  temp that  holds  the address  of  the
			! proper epilogue at runtime

FORWARD
	CGDOLOOP,
	CGDOEND(1),
	CGPROEPI ,
	CGEPILOGUE(1),
	CGRETURN(1),
	CGSFN,
	CGSBPRGM(2),	! Generate code for a subroutine call
	ARGGEN(1),
	CGARGS;

EXTERNAL 
	A1LABEL,
%2313%	BASE A1NODE,	! Points to first argument of expression
	A2LABEL,
	ARGLINKPT,	! Points to linked list of arg blocks
%761%	CALLER,
	CGASMNT,
%1533%	CGCHMRK,	! Generate code for a CHMRK. call
%1533%	CGCHUNW,	! Generate code for a CHUNW. call
	CGCMNSUB,	! Generate code for common subs
%2313%	CGEND,		! Generate code for END statement
	CGERR,
	CGETVAL,
	CGOPGEN,	! Code generation routine
	CLOBBREGS,
%2313%	BASE CSTMNT,	! Points to current statement
	DEFLAB,		! Defines a label
%674%	DOSTAK,
%2313%	E130,		! Error for alternate RETURN with no dummy labels
	E131,
%674%	E144,		! Error message declarations
%1002%	EVALTAB EVALU,	! Maps internal type codes to external
	FATLERR,
	GENLAB,
%2317%	GENREF,		! Constructs memory references
	LASTONE,
	NEDZER,		! Flag to indicate if zero-arg-block needed
%1533%	OBUFF,
	OBUFFA,		! Outputs a word
%1401%	OIFIW,		! Makes the word in PBOPWD into an IFIW
			!  and writes it out with OBUFFA
	OPDSPIX,
%2313%	OPGETI,		! OPGEN table entry for "get in register"
	OPGSFN,
%761%	OPGSTI,
%2313%	OPGZER,		! OPGEN table entry for setting an AC to zero
%2317%	OBJECTCODE PBOPWD,	! Holds data word to output
	PROGNAME,
	PSYMPTR,	! Holds relocation info for OBUFFA
%761%	REGFORCOMP,
%761%	TBLSEARCH,
%2313%	BASE TREEPTR,	! Points to current expression
	ZERBLK;

GLOBAL ROUTINE CGDOLOOP=
BEGIN
	! Code generator drivers for DO loops

%1206%	EXTERNAL DOZJMP,A1LABEL;
	EXTERNAL TREEPTR,A1NODE,A2NODE,REGFORCOMP,CSTMNT;
	EXTERNAL DOSTI;
%761%	EXTERNAL CGETVAL,OPGETI,DOSP,OPGSTI,DOSTC;

	MAP BASE DOSP:A1NODE:CSTMNT:TREEPTR;
	OWN PEXPRNODE DOCEXPR;	! Ptr to expression for control wd
	LOCAL	CTLREG,		! Control word register
		IVALREG;	! Initial value register

	IF .CSTMNT[SRCCOMNSUB] NEQ 0	! Gen code for any common subs
	THEN CGCMNSUB();

	CTLREG = .CSTMNT[DOCREG]^23;	! Set up local values
	IVALREG = .CSTMNT[DOIREG]^23;

	! Get the val of the control expression into the loop ctl reg

	DOCEXPR = .CSTMNT[DOLPCTL];
	A1NODE = .DOCEXPR;

	! If the ctl expr needs to be evaluated at run time, generate code to evaluate it

	IF .DOCEXPR[OPRCLS] NEQ DATAOPR
	THEN
	BEGIN
		TREEPTR = .DOCEXPR;
		CGETVAL();
	END;

	! Get the value of the ctl expression into the loop ctl reg

	IF NOT .CSTMNT[CTLSAMEFLG]
	THEN
	BEGIN
		REGFORCOMP = .CTLREG;
		A1NODE = .DOCEXPR;

		IF .CSTMNT[FLCWD]	! If the ctl is in an AOBJN wd
%761%		THEN	OPDSPIX = OPGETI
		ELSE	OPDSPIX = DOGETAOPIX(.CSTMNT[CTLIMMED], .A1NODE[VALTP1],.CSTMNT[CTLNEG]);
		CGOPGEN();
	END;

	! Control word is now in a register
	! Get the initial value in one if necessary

	IF NOT .CSTMNT[FLCWD] THEN
	BEGIN
		REGFORCOMP = .IVALREG;
		A1NODE = .CSTMNT[DOM1];	! Initial value

		! If the initial val is not in the reg for the DO index, put it there
		IF .A1NODE[OPRCLS] EQL REGCONTENTS
		AND .A1NODE[TARGTAC] EQL .CSTMNT[DOIREG]
		THEN
		BEGIN END
		ELSE 
		BEGIN
			IF .CSTMNT[INITLIMMED]
			THEN	OPDSPIX = DOGETAOPIX(1,.A1NODE[VALTP1],.CSTMNT[INITLNEG])
			ELSE	OPDSPIX = DOGETAOPIX(0,.A1NODE[VALTP1],.CSTMNT[INITLNEG]);
			CGOPGEN();
		END
	END;

	! If this loop must have its count-ctl var materialized, generate code
	! to store the count

	IF .CSTMNT[NEDSMATRLZ] OR .CSTMNT[MATRLZCTLONLY]
	THEN
	BEGIN
		! Generate code to store the count

		A1NODE = .CSTMNT[DOCTLVAR];
		REGFORCOMP = .CTLREG;
		OPDSPIX = DOSTC + .CSTMNT[FLCWD];
		CGOPGEN();
	END;

%1206%	! If this is a potential zero trip loop, we need a label to
%1206%	! jump to at the end of the loop...
%1206%	! Also code to jump around the loop if appropriate.

%1206%	IF F77 THEN
%1206%	IF .CSTMNT[MAYBEZTRIP] NEQ 0 THEN
%1206%	BEGIN
%1206%		EXTERNAL PBOPWD,PSYMPTR,OBUFF;
%1206%		CSTMNT[DOZTRLABEL] = A1LABEL = GENLAB();
%1206%		REGFORCOMP = .CTLREG;

%1206%		IF .CSTMNT[FLCWD] AND NOT .CSTMNT[NEDSMATRLZ] ! Trip count constant
%1227%		AND .DOCEXPR[CONST2L] EQL 0	! Trip count zero
%1206%		THEN	JRSTGEN(.A1LABEL)	! Too late to delete the loop,
%1206%						! but we can still jump around it!
%1206%		ELSE
%1206%		BEGIN	! Put out a JUMPGE on negative count
%1206%			OPDSPIX = DOZJMP;
%1206%			CGOPGEN()
%1206%		END
%1206%	END;

	! If this loop must have its index materialized, generate code to store the index

	IF .CSTMNT[NEDSMATRLZ] OR .CSTMNT[MATRLZIXONLY]
	THEN
	BEGIN
		! Generate the materialization label

		DOSP[LEFTP] = GENLAB();
		DEFLAB(.DOSP[LEFTP]);

		! Now store initial value using opgnta tables to get
		! double precision unless its an HRRM

		IF .CSTMNT[FLCWD] THEN
		BEGIN
			A1NODE = .CSTMNT[DOSYM];	! Induction variable
			REGFORCOMP = .CTLREG;
			OPDSPIX = DOSTI;
			CGOPGEN();
		END
		ELSE
		BEGIN
			REGFORCOMP = .IVALREG;
			TREEPTR = .CSTMNT[DOSYM];
			OPDSPIX = STOROPIX(TREEPTR);
			CGOPGEN();
		END;
	END;

	! Now generate non-materialization labels

	DOSP[RIGHTP] = GENLAB();
	DEFLAB(.DOSP[RIGHTP]);
	DOSP = .DOSP+1;

%674%	! Test for stack overflow, and issue message if necessary
%674%	IF (.DOSP-DOSTAK) GTR TDOSTSIZ THEN FATLERR(.ISN,E144<0,0>);

END;	! CGDOLOOP

GLOBAL ROUTINE CGDOEND(TLAB)=
BEGIN

![761] OPGARG for /GFLOATING code generation
	EXTERNAL REGFORCOMP,TREEPTR,
%761%	A1NODE,A2NODE,DOSP,DOEND,OPGARG,OPGARI,OPGDOE;

%1206%	EXTERNAL OPGETI,OPGDOS,OPGSTI,DOSTI;
	MAP BASE TLAB;
	MAP BASE A1NODE:DOSP:A2NODE:TREEPTR;

	! TLAB points to label table entry for label terminating the scope of
	! one or more do statements.
	! SNDOLNK points to a linked list of the DO statements terminating here

	LOCAL	CURDO,		! the current DO loop
		NXTWD,		! word containing link and do pointer
		NXTLNK,		! word containing link to next word
		TMP1;

	MAP BASE CURDO:TMP1:NXTWD:NXTLNK;

	IF .TLAB[SNDOLVL] EQL 0 THEN RETURN;	! No DO's end here

	NXTWD = .TLAB[SNDOLNK];			! Point at first of list

	WHILE .NXTWD NEQ 0 DO
	BEGIN
		CURDO = .NXTWD[LEFTP];

		! If the loop is still there

%1206%		IF .CURDO NEQ 0 THEN
		IF NOT .CURDO[DOREMOVED] THEN
		BEGIN
			DOSP = .DOSP-1;

			! Look at the correct stack entry determine which
			! label to transfer to at loop ending if the
			! index is materialized, transfer to materialize label

			IF .CURDO[NEDSMATRLZ] OR .CURDO[MATRLZIXONLY]
			THEN	A1LABEL = .DOSP[LEFTP]
			ELSE	A1LABEL = .DOSP[RIGHTP];

			IF .A1LABEL EQL 0 THEN CGERR();

			! For the AOBJN case - the control wd and the loop
			! index are incremented together

			IF .CURDO[FLCWD] AND NOT .CURDO[NEDSMATRLZ]
			THEN
			BEGIN	! Generate AOBJN CREG,A1LABEL

				A1NODE = .CURDO[DOCTLVAR];	! Temp for contol word
				REGFORCOMP = .CURDO[DOCREG]^23;
				OPDSPIX = OPGDOE;
			END
			ELSE
			BEGIN

				! For cases other than AOBJN - must generate
				! code to increment the loop index and code to
				! increment and test the control-word

				REGFORCOMP = .CURDO[DOIREG]^23;

				IF NOT .CURDO[NEDSMATRLZ] AND NOT .CURDO[MATRLZIXONLY]
				THEN
				BEGIN
					! If the loop index is not materialized
					! simply generate an add of the incr to
					! the reg holding the index

					A2NODE = .CURDO[DOSSIZE];	! ptr to incr

					IF (.CURDO[SSIZONE] OR .CURDO[SSIZIMMED])
					AND .A2NODE[VALTYPE] NEQ DOUBLPREC
					THEN	OPDSPIX = DOARITHOPIX(.A2NODE[VALTP1],0,1,.CURDO[SSIZNEGFLG])
					ELSE	OPDSPIX = DOARITHOPIX(.A2NODE[VALTP1],0,0,.CURDO[SSIZNEGFLG]);
					CGOPGEN();
				END
				ELSE
				IF (.CURDO[SSIZONE] AND NOT .CURDO[REALARITH])
	 				OR .CURDO[FLCWD]
				THEN
				BEGIN
					! If the loop index is materialized and
					! the increment is 1, generate AOS

					A1LABEL = .DOSP[RIGHTP];
					OPDSPIX = OPGDOS;	! Non-matrlize label

					A1NODE = .CURDO[DOSYM];
					CGOPGEN();
				END
				ELSE
				BEGIN
					! If the loop index needs to be materialized
					! pick up the increment and them add it
					! to memory if valtype is not double-prec
					A1NODE = .CURDO[DOSSIZE];
					IF (.CURDO[SSIZONE] OR .CURDO[SSIZIMMED])
					AND .A1NODE[VALTYPE] NEQ DOUBLPREC
					THEN OPDSPIX = DOGETAOPIX(1,.A1NODE[VALTP1],.CURDO[SSIZNEGFLG])
					ELSE OPDSPIX = DOGETAOPIX(0,.A1NODE[VALTP1],.CURDO[SSIZNEGFLG]);
					CGOPGEN();

					! Unless the index is double-prec will
					! add the increment to it in both the
					! reg used and memory, and transfer at
					! loop end will be to the code after
					! the materialization code

					A2NODE = .CURDO[DOSYM];
					IF .A2NODE[DBLFLG]
%1206%					THEN	OPDSPIX = DOARITHOPIX(.A2NODE[VALTP1],1,1,0)
					ELSE
					BEGIN
						! Index to generate ADD to both
						! for REAL or INTEGER

						A1LABEL = .DOSP[RIGHTP];
						OPDSPIX = DOARBOTHOPIX(.A2NODE[VALTP1]);
					END;
					CGOPGEN();
				END;

				! generate code to increment and test the control word
				! AOJL
				! OR
				! AOSGE
				! JRST
				! The control register is used

				REGFORCOMP = .CURDO[DOCREG]^23;

				! Code to be generated depends on whether the
				! ctl-count word is materialized

				OPDSPIX = OPGDOE+2+(.CURDO[NEDSMATRLZ] OR .CURDO[MATRLZCTLONLY]);
				A1NODE = .CURDO[DOCTLVAR];
			END;
			CGOPGEN();

%1206%			! If a zero trip label is required, put one out.
%1206%			! Also make sure that the final loop value gets
%1206% 			! generated - handle all the various cases.

%1206%			IF .CURDO[DOZTRLABEL] NEQ 0 
%1206%			THEN DEFLAB(.CURDO[DOZTRLABEL]);

%1276%			IF F77 THEN	! Need to get final value to variable
%1206%			IF NOT .CURDO[MAYBEZTRIP]
%1206%			AND (.CURDO[NEDSMATRLZ] OR .CURDO[MATRLZIXONLY])
%1206%			THEN BEGIN END ! Already got the index materialized
%1206%			ELSE	IF .CURDO[FLCWD] 	! Need to get the final value for loop variable 
%1206%				THEN
%1206%				BEGIN
%1206%					A1NODE = .CURDO[DOSYM];
%1206%					REGFORCOMP = .CURDO[DOCREG]^23;
%1206%					OPDSPIX = DOSTI;
%1206%					CGOPGEN();
%1206%				END
%1206%				ELSE
%1206%				BEGIN
%1206%					REGFORCOMP = .CURDO[DOIREG]^23;
%1206%					TREEPTR = .CURDO[DOSYM];
%1206%					OPDSPIX = STOROPIX(TREEPTR);
%1206%					CGOPGEN();
%1206%				END;
		END;	! Do loop really there test

		NXTLNK = .NXTWD[RIGHTP];
		NXTWD = .NXTLNK;

	END;	! WHILE .NXTWD NEQ 0 DO
END;	! CGDOEND;

MACRO TNAME(INDX)=

	! Defines .A00nn temp names to save the registers used in  the
	! function.  .A0002 to .A0016  are for register saves,  .A0017
	! holds the epilogue address if there are multiple entries.

%1505%	(SIXBIT '.A0000'+(((INDX) AND #70)^3)+((INDX) AND #7))$;

GLOBAL ROUTINE CGPROEPI =
BEGIN
	! Generate subroutine prologue and epilogue, using temps
	! .A0002 to .A0017

	OWN PEXPRNODE ENTNAME;
	LOCAL ARGLSTPT;
	EXTERNAL OPGADJ,A2LABEL;
	EXTERNAL OPGMVL;
%761%	EXTERNAL OPGPHR,OPGPPR,DVALU,OPINSI,CLOBBREGS;
	EXTERNAL OUTMOD,PBFPTR,PBUFF,PBOPWD,OBUFF,OBUFFA,PSYMPTR,C1H;
	EXTERNAL CSTMNT,NAME,TBLSEARCH,ENTRY,POPRET,CRETN,PROGNAME;
%761%	EXTERNAL REGFORCOMP,A1NODE,OPINDI,OPGETI;
%1505%	EXTERNAL BASE TREEPTR;
%1266%	EXTERNAL OPIND2,OPGST2,OPGSTI;
	EXTERNAL XCTFDDT;
	MAP PPEEPFRAME PBFPTR;
	EXTERNAL ARGLINKPT;
	MAP PEXPRNODE CSTMNT:A1NODE;
	MAP ARGUMENTLIST ARGLSTPT;
	MAP PEEPFRAME PBUFF;
	EXTERNAL OUTMDA,OPGIIN;

	PBFPTR[PBFISN] = NOISN;	! Remove the seq number from the next instr
				! (instead it will go on the 1st instr after
				! the entry pt)

	JUMPABOUT = 0;	! If an entry then JRST around prologue	and epilogue

	IF .CSTMNT[SRCID] EQL SFNID THEN
	BEGIN
		JMPSFN = GENLAB();
		JRSTGEN(.JMPSFN);

		! Use A1NODE as a temp to make and save the label for the sfn
		! that will be used in the PUSHJ at reference time

		A1NODE = .CSTMNT[SFNNAME];
		A1NODE[IDSFNLAB] = GENLAB();
	END;

	IF .CSTMNT[ENTNUM] NEQ 0 AND .CSTMNT[SRCID] NEQ SFNID
	THEN
	BEGIN
		JUMPABOUT = GENLAB();
		JRSTGEN(.JUMPABOUT);
	END;

	! Output any instrs remaining in the peephole buffer (and initialize
	! the ptr to next available wd in buffer to the 1st wd of buffer

	IF .PBFPTR NEQ PBUFF
	THEN
	BEGIN
		OUTMOD(PBUFF,(.PBFPTR-PBUFF)/PBFENTSIZE);
		PBUFF[PBFLABEL] = NOLABEL;	! Init label field of 1st instr
		PBFPTR = PBUFF;
	END;

	! Clear ISN field in peephole buffer - want the isn on the 1st instr,
	! not on the sixbit

	PBFPTR[PBFISN] = NOISN;

	! Output sixbit for the entry name. use the output routine OBUFFA to
	! bypass the peephole optimizer

	ENTNAME = .CSTMNT[ENTSYM];
	PBOPWD = .ENTNAME[IDSYMBOL];
	PSYMPTR = PBF2NOSYM;
	OBUFFA();

	! Must now clear the peephole buffer again before start peepholing

	IF .PBFPTR NEQ PBUFF
	THEN
	BEGIN
		OUTMDA(PBUFF,(.PBFPTR - PBUFF) / PBFENTSIZE);
		PBFPTR = PBUFF;
		PBUFF[PBFLABEL] = NOLABEL;
	END;

	! There should be only one subroutine or function per compilation unit.
	! Save the epilogue address if necessary, make the entry name a global
	! for LINK

	IF .CSTMNT[SRCID] NEQ SFNID
	THEN
	BEGIN
		PBOPWD = .CSTMNT[ENTSYM];
		PSYMPTR = PBFENTRY;
		OBUFF();
	END
	ELSE
	BEGIN
		A1NODE = .CSTMNT[SFNNAME];
		DEFLAB(.A1NODE[IDSFNLAB]);
	END;

	PBFPTR[PBFISN] = .CSTMNT[SRCISN];	! Internal seq number of the entry
					! stmnt goes on the 1st instruction
					! of the entry sequence

	! If the user specified /DEB:TRACE, generate "XCT FDDT."

	IF .FLGREG<DBGTRAC> THEN XCTFDDT();

	! Define the epilogue label

	EPILAB = GENLAB();

	IF .FLGREG<MULTENT>
	THEN
	BEGIN	! If multiple entries

		REGFORCOMP = 1^23;	! Hope to generate MOVEM 1, A0017
		A1LABEL = .EPILAB;
		OPDSPIX = OPGMVL;
		NAME = IDTAB;
		ENTRY = TNAME(#17);
		A1NODE = TBLSEARCH();
%1505%		A1NODE[IDPSECT] = PSDATA;	! .A0017 goes in .DATA.

		CGOPGEN();
	END;

	! Save register 16 except if its a statement function or a function
	! that does not call FOROTS or any other functions use PUSH for sfn
	! MOVEM otherwise

	IF .CSTMNT[SRCID] EQL SFNID
	THEN	OPDSPIX = OPGPHR	! Store the other regs using PUSH
	ELSE	IF NOT (.BTTMSTFNFLG AND .IOFIRST EQL 0 AND NOT .LIBARITHFLG)
		THEN
		BEGIN
%761%			OPDSPIX = OPGSTI;
			NAME = IDTAB;
			ENTRY = TNAME(#16);
			TREEPTR = TBLSEARCH();
%1505%			TREEPTR[IDPSECT] = PSDATA;	! .A0016 goes in .DATA.

			REGFORCOMP = #16^23;
			CGOPGEN();
		END
%761%		ELSE OPDSPIX = OPGSTI;	! Will store any other regs using MOVEM

	! Now if it is a function

	IF .FLGREG<PROGTYP> EQL FNPROG
	THEN	DECR I FROM LASTONE(.CLOBBREGS) TO 2 DO
		BEGIN
			IF .CSTMNT[SRCID] EQL ENTRID THEN
			BEGIN
				NAME = IDTAB;
				ENTRY = TNAME(.I);
				TREEPTR = TBLSEARCH();
%1505%				TREEPTR[IDPSECT] = PSDATA;	! In .DATA.
			END;
			REGFORCOMP = .I^23;
			CGOPGEN();
		END;

	! Move args to temps - address of temp is in symbol table for argument

	REGFORCOMP = 0;

%1401%	IF .CSTMNT[ENTLIST] NEQ 0 THEN
	BEGIN
%1401%		ARGLSTPT = .CSTMNT[ENTLIST];
		INCR I FROM 1 TO .ARGLSTPT[ARGCOUNT] DO
		BEGIN	! Walk down args

			TREEPTR = A1NODE = .ARGLSTPT[.I,ARGNPTR];

			IF .A1NODE NEQ 0 THEN		! Zero means label
			IF NOT .ARGLSTPT[.I,ENTNOCOPYFLG]
			THEN
			BEGIN	! Local copy is to be made of this param

%1266%				! For character formals copy the descriptor
%1266%				! Always copy the byte pointer, copy the length
%1266%				! if the formal is length *

%1266%				IF .A1NODE[VALTYPE] EQL CHARACTER
%1266%				THEN
%1266%				BEGIN
%1266%					IF .A1NODE[IDCHLEN] EQL LENSTAR
%1266%					THEN	OPDSPIX = OPIND2	! Copy BP and length
%1266%					ELSE	OPDSPIX = OPINDI;	! Copy BP only
%1266%					C1H = INDBIT OR (.I - 1);	! Set indirect bit and Y field
%1266%				END
%1266%				ELSE
%1266%				BEGIN	! Not character

					IF .A1NODE[OPR1] EQL OPR1C(DATAOPR,FORMLVAR)
					THEN
					BEGIN	! Move value of scalar to register

%761%						OPDSPIX = .A1NODE[VALTP1] + OPINDI;
%761%						C1H = INDBIT OR (.I-1);
					END
					ELSE
					BEGIN
						OPDSPIX = OPGIIN;
						C1H = INDBIT OR (.I-1);
					END
%1266%				END;	! Not character

				! Pick up register from entac field

				REGFORCOMP = .ARGLSTPT[.I,ENTAC]^23;
				CGOPGEN();	! Value now in a register

				! Now store value or pointer in temp

%1266%				IF .A1NODE[VALTYPE] EQL CHARACTER
%1266%				THEN	IF .A1NODE[IDCHLEN] EQL LENSTAR
%1266%					THEN	OPDSPIX = OPGST2	! Copy BP and length
%1266%					ELSE	OPDSPIX = OPGSTI	! Copy BP only
%1266%				ELSE	IF .A1NODE[OPR1] EQL OPR1C(DATAOPR,FORMLVAR)
%761%					THEN	OPDSPIX = .A1NODE[DBLFLG]+OPGSTI
%761%
					ELSE	OPDSPIX = OPGSTI;

				! Only do store if not globally allocated

				IF NOT .ARGLSTPT [.I, ENTGALLOCFLG]
%2317%				THEN CGOPGEN ();
			END;	! Local copy is to be made of this param
		END;	! Walk down args
	END;

	! Now generate JRST to first executable statement

	!**********************************************************************
	!**********************************************************************
	! This JRST  is special.  If we  are going  to create  a  jump
	! vector for  multiple returns,  we must  output the  peephole
	! buffer before  generating  the JRST.  Else,  it would  be  a
	! labeled JRST and  receive cross-jumping optimization.  Since
	! the peephole optimizer always looks  at the third from  last
	! instruction, making it  the first  instruction will  inhibit
	! the peephole.
	!**********************************************************************
	!**********************************************************************

	IF .JUMPABOUT EQL 0 THEN JUMPABOUT = GENLAB();	! Already have label if
							! jumpabout is set

	! If there were label dummy args

	IF .FLGREG<LABLDUM>
	THEN
	BEGIN	! Make this JRST the base of the jump vector so we dont waste a space
		!*****************************************
		! Here is the special output of the buffer
		!*****************************************

		OUTMOD(PBUFF,(.PBFPTR-PBUFF)/PBFENTSIZE);
		PBFPTR = PBUFF;
		PBUFF[PBFLABEL] = NOLABEL;

		JMPVECT = GENLAB();
		DEFLAB(.JMPVECT);
	END;

	! Now JRST to first executable if there are label args (and hence a
	! jump vector) or multiple entries.  This entry follows the prologue

	IF .FLGREG<LABLDUM> OR .FLGREG<MULTENT> THEN JRSTGEN(.JUMPABOUT);

	! Now the rest of the jump vector if needed

	IF .CSTMNT[SRCID] NEQ SFNID	! Don't need it if it's an arithmetic statement function
	THEN	
	BEGIN
		LABARGCT = 0;
		IF .FLGREG<LABLDUM>
		THEN
		BEGIN
			! First output the JRST, it must go thru OUTMOD.
	
			OUTMOD(PBUFF,1);
			PBFPTR = PBUFF;
			PBUFF[PBFLABEL] = NOLABEL;
	
%1401%			IF .CSTMNT[ENTLIST] NEQ 0 THEN
			BEGIN
%1401%				ARGLSTPT = .CSTMNT[ENTLIST];
				INCR I FROM 1 TO .ARGLSTPT[ARGCOUNT] DO
				BEGIN
					IF .ARGLSTPT[.I,ARGNPTR] EQL 0
					THEN	! It is a label
					BEGIN
						! Generate @N-1(16) (which is
						! added to the value of the
						! are list base by a RETURN N)

						LABARGCT = .LABARGCT+1;
%1401%						PSYMPTR = PBF2NOSYM;
%1401%						PBOPWD=(#36^18) OR (.I-1);
%1401%						OIFIW()
					END;
				END;
			END;

			! Now output the jump vector through outmda
	
			OUTMDA(PBUFF,.LABARGCT);
			PBFPTR = PBUFF;
	
		END;
	END;	! End of if statement function

	! For multiple entry subroutines, generate the epilogue right after
	! the prologue for each entry

	IF .FLGREG<MULTENT> THEN CGEPILOGUE(.CSTMNT);

	! Define label of first executable statement

	DEFLAB(.JUMPABOUT);

	! If there are multiple entries (the return will be an indirect JRST)
	! then make EPILAB point to the temp in which the epilogue address is
	! stored.

	IF .FLGREG<MULTENT> THEN
	BEGIN
		NAME = IDTAB;
		ENTRY = TNAME(#17);
		EPILAB = TBLSEARCH();
	END;
END;	! CGPROEPI


GLOBAL ROUTINE CGEPILOGUE(ENTSTMN)=
BEGIN
	! Routine to generate code for function/subroutine epilogue. ENTSTMN
	! points to the entry statement to which this epilogue corresponds

	EXTERNAL A1NODE,C1H,REGFORCOMP;
	EXTERNAL PROGNAME;
	MAP PEXPRNODE A1NODE;
%761%	EXTERNAL OPGETI,POPRET,CRETN,OPINSI,OPGPPR;
	EXTERNAL CLOBBREGS,TBLSEARCH;
	EXTERNAL NAME;
	MAP BASE ENTSTMN;
	REGISTER ARGUMENTLIST ARGLSTPT;

	DEFLAB(.EPILAB);	! Define the epilogue label

	! Restore register 16. Statement functions and bottommost functions
	! won't restore 16 

	IF .ENTSTMN[SRCID] NEQ SFNID
		AND (NOT .BTTMSTFNFLG OR .IOFIRST NEQ 0 OR .LIBARITHFLG)
	THEN
	BEGIN
		NAME = IDTAB;
		ENTRY = TNAME(#16);
		A1NODE = TBLSEARCH();
%761%		OPDSPIX = OPGETI;
		REGFORCOMP = #16^23;
		CGOPGEN();
	END;

	! For labels as parameters generate the complex return

	IF .FLGREG<LABLDUM>
	THEN
	BEGIN
		A2LABEL = .JMPVECT;
		A1LABEL = GENLAB();	! Label for out of bounds
		C1H = .LABARGCT;
		OPDSPIX = CRETN;
		CGOPGEN();
		DEFLAB(.A1LABEL);
	END;

	! Now move scalars back. Not necessary for  statement functions

%1401%	IF .ENTSTMN[ENTLIST] NEQ 0 AND .ENTSTMN[SRCID] NEQ SFNID
	THEN
	BEGIN
		REGFORCOMP = 0;
%1401%		ARGLSTPT = .ENTSTMN[ENTLIST];
		INCR I FROM 1 TO .ARGLSTPT[ARGCOUNT] DO
		BEGIN	! Walk down args

			A1NODE = .ARGLSTPT[.I,ARGNPTR];

			IF .A1NODE NEQ 0 THEN
			IF NOT .ARGLSTPT[.I,ENTNOCOPYFLG]
			THEN
			BEGIN	! Local copy was made of this param

				! Only move them back if they were stored into,
				! else we are in trouble with generating hiseg
				! stores. Never copy back character descriptors

				IF .A1NODE[IDATTRIBUT(STORD)] THEN
%1266%				IF .A1NODE[VALTYPE] NEQ CHARACTER THEN
				IF .A1NODE[OPR1] EQL OPR1C(DATAOPR,FORMLVAR) THEN
				IF NOT .ARGLSTPT[.I,ENTGALLOCFLG] THEN
				BEGIN
					! Local case - set regforcomp.
					! Things are different if global
					! allocation of an argument has
					! occurred

					REGFORCOMP = (IF .ENTSTMN[VALINR0] THEN
					1^23 ELSE 0);
					C1H = INDBIT OR (.I-1);
%761%					OPDSPIX = .A1NODE[VALTP1]+OPGETI;
					CGOPGEN();
%761%					OPDSPIX = .A1NODE[DBLFLG]+OPINSI;
					CGOPGEN();
				END
				ELSE
				BEGIN	! Globally allocated

					REGFORCOMP = .ARGLSTPT[.I,ENTAC]^23;
					C1H = INDBIT OR (.I-1);
%761%					OPDSPIX = .A1NODE[DBLFLG]+OPINSI;
					CGOPGEN();
				END;
			END;	! Local copy was made of this param
		END;	! Walk down args
	END;

	IF .ENTSTMN[SRCID] EQL SFNID	! Restore registers if need be
	THEN	OPDSPIX = OPGPPR
%761%	ELSE	OPDSPIX = OPGETI;

	NAME = IDTAB;

	IF .FLGREG<PROGTYP> EQL FNPROG
	THEN
	BEGIN
		!******************************************************
		! Since statement functions PUSH and POP for register
		! save and restore, these must be symetrically reversed
		! to the save code in the prologue
		!******************************************************

		INCR I FROM 2 TO LASTONE(.CLOBBREGS) DO
		BEGIN
			IF .ENTSTMN[SRCID] EQL ENTRID THEN
			BEGIN
				ENTRY = TNAME(.I);
				A1NODE = TBLSEARCH();
			END;

			REGFORCOMP = .I^23;
			CGOPGEN();
		END;

		A1NODE = .ENTSTMN[ENTSYM];	! Name of fn

		IF NOT .A1NODE[IDATTRIBUT(STORD)]
			AND NOT .ENTSTMN[SRCID] EQL SFNID
		THEN FATLERR(.ISN,E131<0,0>);	! If the value is never stored

%1422%		! Pick up return function value  for if not already put  there
%1422%		! by global allocator.  Don't  do it for character  functions.
%1422%		! Character functions have  the descriptor for  the result  as
%1422%		! their first argument.

%1422%		IF NOT .ENTSTMN[VALINR0] THEN
%1422%		IF .A1NODE[VALTYPE] NEQ CHARACTER
		THEN
		BEGIN
			REGFORCOMP = 0;
%761%			OPDSPIX = .A1NODE[VALTP1]+ OPGETI;
			CGOPGEN();
		END;
	END;	! FNPROG

	OPDSPIX = POPRET;
	CGOPGEN();
END;	! CGEPILOGUE

MACRO JRSTIVAR(ADDR)=
BEGIN

	! Macro to generate an indirect JRST through a variable.
	! Differs from JRSTIGEN in the setting of PSYMPTR

	PBOPWD = JRSTOC OR INDBIT OR ADDR[IDADDR];
	PSYMPTR = ADDR;
	OBUFF();
END$;

GLOBAL ROUTINE CGRETURN(EXPR) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine  generates code  for RETURN  statements.  If  the
!	RETURN is a plain  RETURN right before  the END statement,  no
!	code is  generated  since  the  code  generated  for  the  END
!	statement will perform the RETURN.
!
!	If the  RETURN  is in  a  main  program, CGEND  is  called  to
!	generate code  for CALL  EXIT. (which  is how  a main  program
!	ends).
!
!	If the RETURN is in a routine without dummy label  parameters,
!	it generates a JRST to the epilogue label (indirectly  through
!	.A0017 if it has multiple ENTRY points).
!
!	If  the  RETURN  is  in  a  routine  which  has  dummy   label
!	parameters, it moves the  alternate RETURN index (defaults  to
!	zero for a plain RETURN) to AC 1, then generates a JRST to the
!	epilogue label as above.
!
! FORMAL PARAMETERS:
!
!	EXPR		Points to the return expression (0 if none)
!
! IMPLICIT INPUTS:
!
!	CSTMNT		Points to the current statement
!
!	EPILAB		Points to the epilogue label of the current program
!			unit
!
!	FLGREG		Flag register; contains information about current
!			program unit
!
! IMPLICIT OUTPUTS:
!
!	A1NODE		Points to first argument of expression
!
!	OPDSPIX		Pointer into the OPGENTABLE dispatch table
!
!	REGFORCOMP	Bits 9-12 indicate the register to be used in
!			the computation for which code is being generated
!
!	TREEPTR		Points to expression to be evaluated
!
! ROUTINE VALUE:
!
!	None
!
! SIDE EFFECTS:
!
!	None
!
!--


![2313] Rewritten

BEGIN
	MAP BASE EXPR;			! EXPR is 0 or points to an expression

	REGISTER BASE NXTSTMNT;		! Used for pointer to next statement

	IF NOT .FLGREG<LABLDUM>		! Are dummy labels absent?
	THEN IF .EXPR NEQ 0		! Yes, do we have an expression?
	THEN FATLERR(.ISN, E130<0,0>);	! Yes, give an error message

	! Check to see if we have a plain RETURN right before the  END
	! statement.  If so, we won't bother to generate any code  for
	! the RETURN.

	IF .EXPR EQL 0					! Plain RETURN?
	THEN IF (NXTSTMNT = .CSTMNT[SRCLINK]) NEQ 0	! Yes, check next stmnt
	THEN
	BEGIN	! Plain RETURN with non-zero SRCLINK

		! We have a plain RETURN which is not the branch of  a
		! logical IF and we're not being called by CGEND.  See
		! if we're at the last  statement in the program  unit
		! before the END statement.

		! Skip  the   CONTINUE  statement   inserted  by   the
		! optimizer (if any).  Make sure it's a dummy CONTINUE
		! by checking for a zero source statement number.

		IF .NXTSTMNT[SRCID] EQL CONTID		! Is next a CONTINUE?
		THEN IF .NXTSTMNT[SRCISN] EQL 0		! Yes, is ISN zero?
		THEN NXTSTMNT = .NXTSTMNT[SRCLINK];	! Yes, skip it

		! If next statement  is the END  statement then  don't
		! generate the RETURN.   It will  be part  of the  END
		! code.

		IF .NXTSTMNT[SRCID] EQL ENDID	! Is the next stmnt the END?
		THEN RETURN;			! Yes, don't bother

	END;	! Plain RETURN with non-zero SRCLINK

	! A RETURN that appears in a main program will be treated like
	! a CALL EXIT. by CGEND.

	IF .FLGREG<PROGTYP> EQL MAPROG
	THEN
	BEGIN	! Main program

		CGEND();	! Generate the call to EXIT.
		RETURN;		! Done

	END;	! Main program

	IF .FLGREG<LABLDUM>	! Do dummy labels exist?
	THEN
	BEGIN	! Dummy labels exist

		IF .EXPR EQL 0			! Plain RETURN?
		THEN OPDSPIX = OPGZER		! Yes, treat as RETURN 0
		ELSE
		BEGIN	! We have an expression

			IF .EXPR[OPRCLS] NEQ DATAOPR
			THEN
			BEGIN	! Must evaluate

				TREEPTR = .EXPR;	! Evaluate EXPR
				CGETVAL();		! Do it

			END;	! Must evaluate

			A1NODE = .EXPR;		! Source is EXPR
			OPDSPIX = OPGETI;	! Get in register (one word,
						! no flags)

		END;	! We have an expression

		REGFORCOMP = 1^23;	! Destination is AC 1
		CGOPGEN();		! Move alternate RETURN index

	END;	! Dummy labels exist

	IF .FLGREG<MULTENT>		! Do multiple entries exist?
	THEN JRSTIVAR(.EPILAB)		! Yes, generate indirect jump
	ELSE JRSTGEN(.EPILAB);		! No, generate direct jump

END;	! of CGRETURN

GLOBAL ROUTINE CGSFN=
BEGIN

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

	! Code generation for statement function

	OWN
		OCSTMNT,
		OCLOBB,
		OPRGM,
		OPE,
		SFNSYM,
		OEPILB;

	MAP
		BASE CSTMNT,
		BASE SFNSYM;

	! Save away pertinent globals

	OCLOBB = .CLOBBREGS;	! Current set of clobbered registers
	OPRGM = .PROGNAME;	! Program name for this unit
	OPE = .FLGREG<0,36>;	! Current flag register
	OCSTMNT = .CSTMNT;	! Current statement pointer
	OEPILB = .EPILAB;	! Current epilog label

	! Adjust flgreg

	FLGREG<PROGTYP> = FNPROG;	! This is a function subprogram
	FLGREG<MULTENT> = 0;		! Statement functions have one entry
	FLGREG<LABLDUM> = 0;		! No dummy labels

	! Setup clobbregs  with  registers clobbered  by  the  statement
	! function

	CLOBBREGS<LEFT> = .CSTMNT[SFNCLBREG];

	! Get the statement function name -  it is put out in SIXBIT  to
	! the .REL file for traceback

	SFNSYM = .CSTMNT[SFNNAME];
	PROGNAME = .SFNSYM[IDSYMBOL];	

	CGPROEPI();			! Generate prologue & epilogue
	CSTMNT = .CSTMNT[SFNEXPR];	! Get the assignment or call node

	IF .SFNSYM[VALTYPE] EQL CHARACTER
	THEN
	BEGIN	! Generate code for a call

		! Generate code for any common subs

		IF .CSTMNT[SRCCOMNSUB] NEQ 0 THEN CGCMNSUB();

		! Generate code for the call to CHSFN. or CHSFC.

		CGSBPRGM(.CSTMNT[CALLIST],.CSTMNT[CALSYM]);	

	END	! Generate code for a call
	ELSE	CGASMNT();		! Generate code for an assignment

	CGEPILOGUE(.OCSTMNT);		! Generate the epilogue code

	! Restore the saved globals

	CLOBBREGS = .OCLOBB;		! Clobbered registers
	PROGNAME = .OPRGM;		! Program name
	FLGREG<0,36> = .OPE;		! Flag register
	CSTMNT = .OCSTMNT;		! Current statement
	EPILAB = .OEPILB;		! Epilog label

	DEFLAB(.JMPSFN);	! Define the label for the start of  the
				! statment function

END;	! CGSFN

GLOBAL ROUTINE CGSBPRGM(ARLISTT,NAMEP)=
BEGIN
!++
! Perform vital code generation for argument lists of
!	o subroutine calls,
!	o function references,
!	o library function references,
! 	o statement function references.
!
! ARLISTT is a pointer to the argument list.
! NAMEP is a pointer to  the symbol table entry for the routine name.
!--
	MAP	BASE NAMEP,
		ARGUMENTLIST ARLISTT;

	LOCAL
%1533%		HASMULTRETS,	! Flag for has multiple returns
%1533%		JRSTPAST;	! The label for the instruction after the error
%1533%				! handling code

	REGISTER
		BASE ARGNODE,	! Argument node in the arg list
%1533%		MARK,		! The ARGMARK field
%1533%		CURLBL;		! The label for the current location


%1533%	HASMULTRETS = FALSE;

%2245%	IF .ARLISTT NEQ 0
	THEN
	BEGIN	! arguments present

%1533%		! If there  are  dynamic  concatenations  as  arguments,
%1533%		! generate the CHMRK. call

%1533%		MARK = .ARLISTT[ARGMARK];
%1533%		IF .MARK NEQ 0 THEN CGCHMRK(.MARK);

		ARLISTT[ARGLINK] = .ARGLINKPT;
		ARGLINKPT = .ARLISTT;

		INCR I FROM 1 TO .ARLISTT[ARGCOUNT] DO
		BEGIN	! Generate code to evaluate arguments

			ARGNODE = .ARLISTT[.I,ARGNPTR];	! Pick up arg ptr

%1533%			! Set the flag if an argument is a label

%1533%			IF .ARGNODE[OPRCLS] EQL LABOP
%1533%			THEN HASMULTRETS = TRUE;

			IF NOT .ARLISTT[.I,AVALFLG]
			THEN
			BEGIN	! Not DATAOPR
				TREEPTR = .ARGNODE;
				CGETVAL();
			END
			ELSE
			BEGIN	! DATAOPR

				! If its a register and a library  function
				! stash  it  away  in  memory.  If  it's  a
				! register and not a library function  then
				! you lose

				IF .ARGNODE[OPRCLS] EQL REGCONTENTS THEN
				BEGIN
					MAP PEXPRNODE TREEPTR;
					TREEPTR = .ARGNODE[ARG2PTR];
					REGFORCOMP = .ARGNODE[TARGTAC]^23;
					OPDSPIX = STOROPIX(TREEPTR);
					CGOPGEN();

					! Take the regcontents node out
					! so the arg list will be right

					ARLISTT[.I,ARGNPTR] = .ARGNODE[ARG2PTR];
				END;
			END;	! DATAOPR
		END;	! Generate code to evaluate arguments


		! If there are arguments, then generate a label for  the
		! argument list.  If not, then  use the shared zero  arg
		! block.

%2245%		IF .ARLISTT[ARGCOUNT] NEQ 0 THEN
			A1LABEL = ARLISTT[ARGLABEL] = GENLAB()	! Gen label
%2245%		ELSE
%2245%		BEGIN	! No arguments
%2245%			NEDZER  =  1;		! Flag zero-arg-block needed
%2245%			A1LABEL = ARLISTT[ARGLABEL] = .ZERBLK;
%2245%		END;

	END	! arguments present
	ELSE
	BEGIN	! No arguments

%1533%		MARK = 0;	! No argument list

		! Reference a common 2 word zero arg block, defined once
		! per program unit.

		NEDZER  =  1;		! Flag zero-arg-block needed
		A1LABEL = .ZERBLK;
	END;

	! For a formal function set the indirect bit in the symbol table
%1455%	! Do not set the indirect bit for character statement functions

%1455%	IF (.NAMEP[IDATTRIBUT(DUMMY)] AND NOT .NAMEP[IDATTRIBUT(SFN)])
	THEN NAMEP[TARGET] = .NAMEP[TARGET] OR INDBIT;

	IF .NAMEP[IDATTRIBUT(SFN)]
	THEN
	BEGIN
		A2LABEL = .NAMEP[IDSFNLAB];
		OPDSPIX = OPGSFN;
	END
	ELSE
	BEGIN
		A1NODE = .NAMEP;
		OPDSPIX = CALLER;
	END;

	CGOPGEN();	! Generate the subprogram call

%1533%	! If there are dynamic concatenations as arguments, generate the
%1533%	! CHUNW. call

%1533%	IF .MARK NEQ 0 THEN CGCHUNW(.MARK);

%1533%	! If there are multiple returns, generate special error handling
%1533%	! code

%1533%	IF .HASMULTRETS
%1533%	THEN 	IF .MARK NEQ 0
%1533%	THEN
%1533%	BEGIN	! Multiple returns

%1533%		! Generate a  label for  the  location after  the  error
%1533%		! handling code

%1533%		JRSTPAST = GENLAB();

%1533%		JRSTGEN(.JRSTPAST);	! Generate JRST JRSTPAST

%1533%		INCR I FROM 1 TO .ARLISTT[ARGCOUNT]
%1533%		DO
%1533%		BEGIN	! Walk down arguments to generate error handling code

%1533%			ARGNODE = .ARLISTT[.I,ARGNPTR];	! Pointer to argument

%1533%			IF .ARGNODE[OPRCLS] EQL LABOP
%1533%			THEN
%1533%			BEGIN	! Argument is a multiple return

%1533%				! Generate a label for the current address

%1533%				CURLBL = GENLAB();
%1533%				DEFLAB(.CURLBL);

%1533%				! Replace the user specified label with the
%1533%				! compiler generated one

%1533%				ARLISTT[.I,ARGNPTR] = .CURLBL;

%1533%				! Generate the CHUNW. call

%1533%				CGCHUNW(.MARK);

%1533%				! Generate JRST user_label

%1533%				JRSTGEN(.ARGNODE);

%1533%			END;	! Argument is a multiple return

%1533%		END;	! Walk down arguments to generate error handling code

%1533%		DEFLAB(.JRSTPAST);	! Define the label for the instruction
%1533%					! after the error handling code.

%1533%	END;

END;	! CGSBPRGM

GLOBAL ROUTINE ARGGEN(PTR)=

!++
! FUNCTIONAL DESCRIPTION:
!
!	Generate an arg block entry for an expression node.  Unlike
!	FOROTS arg block generation (IOPTR), this routine does not
!	allow its caller to fill in any of the fields in PBOPWD.
!
! FORMAL PARAMETERS:
!
!	PTR		Points to expression node for argument.
!
! IMPLICIT INPUTS:
!
!	EVALU		Used to map PTR[VALTYPE] into argument type code.
!
! IMPLICIT OUTPUTS:
!
!	PBOPWD		Destroyed.
!
!	PBUFF		Peephole buffer gets the finished arg block word.
!
!	PSYMPTR		Destroyed.
!
! ROUTINE VALUE:
!
!	None
!
! SIDE EFFECTS:
!
!	Could flush the peephole buffer into the object and listing files.
!
!--


![1401] Rewritten to support extended addressing

BEGIN

!=========================================================================!
!1!0!      0      ! Type  !I! Index  !              Address               !
!=========================================================================!

MAP PEXPRNODE PTR;			! Points to the expression

	PBOPWD = 0;			! Start out with an empty word

	![1524] If PTR is not character then we want to set the
	![1524] indirect bit if it is a formal function name.

	! [Remark by RVM: I don't understand this comment.]

	! The indirect bit may already have been set if it was
	! previously referenced as a formal function.  Thus we set the
	! bit explicitly.

%2317%	IF .PTR[OPRCLS] EQL DATAOPR
%1524%	THEN IF .PTR[VALTYPE] NEQ CHARACTER
	THEN IF (.PTR[FORMLFLG] AND .PTR[IDATTRIBUT(INEXTERN)])
	THEN PBOPWD[OTSIND] = 1;

	IF .PTR[OPRCLS] EQL LABOP
	THEN PBOPWD[OTSTYPE]=ADDRTYPE
%1002%	ELSE PBOPWD[OTSTYPE]=.EVALU[.PTR[VALTYPE]];

%2317%	PBOPWD[OTSIFIW] = 1;		! Make the word an IFIW
%2462%	GENREF(.PTR,TRUE);		! Construct memory reference for
					!  argument word and buffer it
END;	! ARGGEN

GLOBAL ROUTINE CGARGS=
BEGIN

![1401] Rewritten to support extended addressing

!++
! At the  end of  a block,  generate any  argument lists  that have  not
! already been  generated.  They  are on  a linked  list pointed  to  by
! ARGLINKPT.  The object code for an arg  list is a labeled vector of  n
! IFIWs to  arguments,  preceeded by  "-n,,0".   The routine  ARGGEN  is
! called to output words that point to the arguments.
!--

	REGISTER ARGCT;			! Will hold number of args
%1437%	REGISTER BASE LABTAB;		! Label table entry
%1437%	REGISTER ARGUMENTLIST ARGLSTPT;	! Arg blocks pointed to by ARGLINKPT


%1437%	ARGLSTPT = .ARGLINKPT;		!The global pointer to all arguments

%1437%	WHILE .ARGLSTPT NEQ 0
	DO
	BEGIN	! For all arg lists . . .

		! Watch out for statements that may have been deleted by
		! folding.  ARGLABEL is 0 for these statements.
%2245%		! Also do not generate an argument block if there are no
%2245%		! arguments.  This  could  exist for  argument  checking
%2245%		! purposes.

		IF .ARGLSTPT[ARGLABEL] NEQ 0
%2245%			AND .ARGLSTPT[ARGCOUNT] NEQ 0	! Any arguments?
		THEN
		BEGIN	! Generate argument block

			ARGCT=.ARGLSTPT[ARGCOUNT];
			PBOPWD=(-.ARGCT)^18;		! -n,,0
			PSYMPTR=PBF2NOSYM;
			OBUFFA();			! Write out count word

			! Save away  the  location  of the  call  using  the
			! label, which is the last reference.  Make sure the
			! label's been referenced, but not resolved.

%1437%			IF .FLGREG<OBJECT>
%1437%			THEN		!.REL file
%1437%			BEGIN
%1437%				LABTAB = .ARGLSTPT[ARGLABEL];
%1437%				IF .LABTAB[SNDEFINED] AND	!Referenced
%1437%				(.LABTAB[SNSTATUS] EQL UNRESOLVED)!Not resolved
%1526%				THEN	ARGLSTPT[ARGCALL] = .LABTAB[SNADDR]
%1437%				ELSE	CGERR();
%1437%			END;

%1437%			!** Here the label is defined***
			DEFLAB(.ARGLSTPT[ARGLABEL]);	! "nnnnnM:"

%1466%			INCR I FROM 1 TO .ARGCT	! Write out each arg
			DO ARGGEN(.ARGLSTPT[.I,ARGNPTR]);

		END;	! Generate argument block

%1437%		ARGLSTPT = .ARGLSTPT[ARGLINK]		! Move to next arg list

	END	! For all arg lists . . .

END;	! of CGARGS

! Below is for RUNOFF in generating .PLM files
!++
!.END LITERAL
!--

END
ELUDOM