Google
 

Trailing-Edge - PDP-10 Archives - BB-4157D-BM - sources/cgexpr.bli
There are 26 other files named cgexpr.bli in the archive. Click here to see a list.


!THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
!  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.

!COPYRIGHT (C) 1972,1977 BY DIGITAL EQUIPMENT CORPORATION
!AUTHOR: S. MURPHY/HPW/DCE
MODULE	CGEXPR(SREG=#17,VREG=#15,FREG=#16,DREGS=4,RESERVE(0,1,2,3)) =
BEGIN

GLOBAL BIND CGEXV = 4^24 + 2^18 + 72;	!VERSION DATE: 24-MAR-77

%(
REVISION HISTORY

63	-----	-----	DECLARE CODE GENERATORS FOR DABS IN LINE
			EXTERNAL
64	-----	-----	MAKE IN LINE EXPONEN TO MEMORY WORK

65	-----	-----	MAKE IN LINE EXPONEN OF DP AND OF IMMED
			LOOP INDEX WORK
66	-----	-----	REMOVE ALL REFERENCES TO SQUARE,CUBE,P4
67	-----	-----	IN "CGVBOOL", SHOULD NOT SKIP THE CALL
				TO CGOPGEN TO GET THE VAL OF ARG1
			IF A1NOTFLG OR A1NEGFLG IS SET
68	-----	-----	CLEAN UP "CGCBOOL"
69	-----	-----	FIX BUG IN EDIT 68
70	-----	-----	IN CGVBOOL, WHEN ARG1 IS A MASK, ARG2 OF TYPE
			CONTROL, SHOULD NOT GENERATE CODE TO STORE
			THE VALUE OF ARG1 INTO A TMP IF "A1SAMEFLG"
			IS SET (INDICATING THAT ITS ALREADY THERE)
71	337	17305	IN CGOPGEN, ROUND UP REAL IMMEDIATE CONSTANTS
			BEFORE SENDING TO LISTING
72	554	22324	FIX CODE GEN FOR AND NODE WITH A1NOTFLG SET
)%

	EXTERNAL CGERR,OUTMOD, PEEPOPTIMZ, CGSBPRGM, CGARREF, 
	OPCMGET,OPGETA,OPGETI,OPGARI,OPGARA,OPGSTA,OPGSTI,OPGN1A,OPGN1I,OPGN2A,OPGN2I,
	OPGDBF,OPGDB1,			!FOR DABSIN LINE
		OPGSPA,OPGSPI,OPGSPM,OPP21I,OPCUBI,OPGILF,OPGILI,OPGIL1,OPGSTC,
	OPGBOO,OPGSET,OPGVTS,OPGALT,OPGREL,OPGTCA,OPGTCI,
	OPGENDISP;

	FORWARD CGEXCIOP(0);
	FORWARD CGETVAL(0), CGOPGEN(0), CGARGEVAL(0),CGILF(0),  CGVBOOL(0),
	CGCBOOL(2), CGREL1(1), CGJMPC(2), DEFLAB(0);

EXTERNAL PROPNEG;	!ROUTINE TO PROPAGATE A NEG OVER ARITH AND TYPECNV NODES,
			! FOUND IN MODULE UTIL
EXTERNAL GENLAB;

EXTERNAL	TREEPTR,CSTMNT,A1NODE,A2NODE,A1LABEL,A2LABEL,A3LABEL,C1H,
		OPDSPIX,REGFORCOMP,PC,PBOPWD,
		PSYMPTR,GBYSREGS,RESNAME;
EXTERNAL NEWENTRY;
EXTERNAL	PBUFF,PBFPTR,PEEPPTR;
EXTERNAL	ADDLAB;
EXTERNAL OPGSTD;

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



	%(***MAP STRUCTURES ONTO THE GLOBAL PTRS USED TO LOOK AT THE CURRENT NODE
		IN THE TREE AND ITS 2 SUBNODES***)%
MAP PEXPRNODE TREEPTR:A1NODE:A2NODE;

MAP BASE CSTMNT;


%(*********SET UP PEEPHOLE BUFFER********************)%

MAP VECTOR PBUFF;

BIND PBFEND=PBUFF+PBFENTSIZE*PBFENTCT;	!PTR TO THE WD AFTER THE END OF THE LAST
					! ENTRY IN THE PEEPHOLE BUFFER 


MAP PPEEPFRAME PBFPTR;		!PTR TO NEXT AVAILABLE WD IN PEEPHOLE BUFFER
					! (WHEN THE BUFFER IS FULL, THIS WILL ALWAYS PT TO AN EXTRA
					! WD AFTER THE END OF THE BUFFER
					! THIS WD WILL OFTEN CONTAIN A LABEL CORRESPONDING
					! TO THE NEXT INSTR TO BE GENERATED

MAP PEEPFRAME PBUFF;

GLOBAL ROUTINE OBUFF=
%(***************************************************************************
	ROUTINE TO OUTPUT INSTRUCTIONS TO THE PEEPHOLE BUFFER.
	CALLED WITH THE GLOBALS
		PBOPWD - THE INSTRUCTION WORD TO GO INTO THE PEEPHOLE BUFFER
		PSYMPTR - PTR TO THE SYMBOL TABLE ENTRY CORRESPONDING
			TO THE ADDRESS FIELD OF THE INSTRUCTION TO BE GENERATED
			(OR  0 IF ADDR FIELD IS A LABEL, 1 IF ADDR FIELD
			IS NOT A SYMBOL - EG IS A REGISTER)
	PUTS THE INSTR IN THE PEEPHOLE BUFFER AND CALLS THE PEEPHOLER
***************************************************************************)%
BEGIN
	%(****IF PEEPHOLE-BUFFER IS FULL, OUTPUT THE TOP BLOCK
		OF INSTRUCTIONS. THE NUMBER OF INSTRS PROCESSED AT A TIME
		IS SPECIFIED BY "PBFOUTCT" WHICH IS BOUND IN "TABLES.BLI".
		MOVE  UP THE REST OF THE INSTRS IN THE BUFFER (MUST LEAVE
		ENOUGH INSTRS IN THE BUFFER TO USE IN PEEPHOLING NEW INSTRS
		THAT WILL BE ADDED).*********)%
	IF .PBFPTR GEQ PBFEND
	THEN
	BEGIN
		OUTMOD(PBUFF,PBFOUTCT);
		BLOCKTR((PBUFF+PBFOUTSIZ),PBUFF,(PBFSIZE-PBFOUTSIZ));
		PBFPTR_PBUFF+(PBFENTCT-PBFOUTCT)*PBFENTSIZE;	!PTR TO THE START OF
						! OF THE FIRST ENTRY AFTER THE SET OF ENTRIES
						! THAT WERE MOVED UP IN THE BUFFER
	END;
	%(****WRITE THE NEW INSTR IN THE FIRST AVAILABLE SLOT****)%
	PBFPTR[PBFSYMPTR]_.PSYMPTR;
	PBFPTR[PBFINSTR]_.PBOPWD;
	PBFPTR_.PBFPTR+PBFENTSIZE;

	%(***INIT THE LABEL FIELD OF THE NEXT INSTR TO 0*****)%
	PBFPTR[PBFLABEL]_0;

	%(***INIT THE ISN (SEQ NUMBER FOR STMNT) FIELD OF THE NEXT INSTR TO CODE FOR
		"NO ISN ON THIS INSTR" ***)%
	PBFPTR[PBFISN]_NOISN;




	%(****PERFORM ANY PEEPHOLE OPTIMIZATIONS TRIGGERED BY THIS INSTRUCTION****)%

	%(***IF THERE ARE FEWER THAN 5 INSTRS IN THE BUFFER, DO NOT
		PEEPHOLE OPTIMIZE YET***)%
	IF (.PBFPTR-PBUFF) GEQ 5*PBFENTSIZE
	THEN
	BEGIN
		PEEPPTR_.PBFPTR-3*PBFENTSIZE;		!PTR TO WD OFF WHICH PEEPHOLES WILL
							! BE KEYED

		PEEPOPTIMZ();
	END;

END;

GLOBAL ROUTINE OBUFFA=
%(***************************************************************************
	ROUTINE TO OUTPUT ARGBLOCK ELEMENTS INTO THE PEEPHOLE BUFFER.
	CALLS THE OUTPUT MODULE FOR EVERY 25 ARGS.
	CALLED WITH THE GLOBALS
		PBOPWD - THE ARGUMENT WD TO BE OUTPUT
		PSYMPTR - PTR TO THE SYMBOL TABLE ENTRY FOR THE
			SYMBOL IN THE RIGHT HALF OF THE ARG-WD
			OR:
				"PBF2NOSYM" - IF BOTH HALVES OF THE WD ARE
						OCTAL CONSTANTS
				"PBF2LABREF" - IF BOTH HALVES OF THE WD ARE PTRS
						TO LABEL TABLE ENTRIES
				"PBFLABREF" - IF LEFT HALF IS AN OCTAL CONSTANT,
						RIGHT HALF IS A PTR TO A LABEL TABLE
						ENTRY
			IF PSYMPTR IS A PTR TO A SYMBOL TABLE ENTRY, THEN
			CAN ASSUME THAT THE LEFT HALF OF THE ARGWD IS AN OCTAL
			CONSTANT
***************************************************************************)%
BEGIN
	EXTERNAL OUTMDA;
	%(***ADD THIS WD TO THE BUFFER***)%
	PBFPTR[PBFSYMPTR]_.PSYMPTR;
	PBFPTR[PBFINSTR]_.PBOPWD;
	PBFPTR_.PBFPTR+PBFENTSIZE;

	%(***IF THE BUFFER IS FULL, OUTPUT ITS CONTENTS**)%
	IF .PBFPTR EQL PBFEND
	THEN
	BEGIN
		OUTMDA(PBUFF,PBFENTCT);
		PBFPTR_PBUFF;
	END;

	%(***INIT THE LABEL FIELD OF THE NEXT INSTR TO 0***)%
	PBFPTR[PBFLABEL]_0;
END;


GLOBAL ROUTINE CGEXCIOP=
%(**********************************************************************

	ROUTINE TO GENERATE CODE FOR SPECOP EXCIOP
	CALLED WITH TREEPTR, A1NODE, A2NODE, REGFORCOMP
	SET UP

**********************************************************************)%
BEGIN
EXTERNAL OPGEX,OPGEXM,OPGEXS,OPGXPI;		!GENERATORS
REGISTER CN[2];
LOCAL MULDPIX;
LOCAL EXPDPIX;
LOCAL MULMIX;	!TO MULTIPLY TO MEMORY
LOCAL TYP;	!VALTP1 OF THE OPERAND
MACHOP LSHC=#246;

TYP_.A1NODE[VALTP1];	!INTEGER,REAL,OR DP(DP ON KI ONLY)
IF .TREEPTR[MEMCMPFLG]	!IF THIS OP IS TO BE DONE TO MEMORY
THEN
BEGIN
	MULMIX_OPGEXM+.TYP;
	IF .A2NODE EQL 2		!SQUARE IS AN EXCEPTION IN THAT
	THEN				! IT CAN BE DONE TO MEMORY EVEN THO AN EVEN POWER
	BEGIN
		OPDSPIX_.MULMIX;
		CGOPGEN();		!GENERATE THE MULTIPLY TO MEMORY FORI=I**2
		RETURN
	END;
END;

MULDPIX_IF .TREEPTR[A1IMMEDFLG] THEN OPGXPI	!TO MULTIPLY AN IMMED LP INDEX
	ELSE OPGEX+.TYP;		! TO MULTIPLY BY THE VAR
EXPDPIX_OPGEXS+.TYP;	!TO MULTIPLY BY SELF
CN[0]_0;		!CLEAR GENERATOR
CN[1]<18,18>_.A2NODE;	!LOAD PATTERN
WHILE .CN[0] NEQ 1 DO LSHC(CN,1);	!JUSTIFY PATTERN
IF .CN[0] EQL .A2NODE THEN RETURN ELSE DO
BEGIN
	LSHC(CN,1);			!GET NEXT POWER
	OPDSPIX_.EXPDPIX;		!MULTIPLY BY SELF
	CGOPGEN();			!GENERATE MULTIPLY
	IF .CN THEN
	BEGIN
		IF .CN[0] EQL .A2NODE	!IF THIS IS THE LAST MULTIPLY
			AND .TREEPTR[MEMCMPFLG]	! AND RESULT IS TO GO TO MEMORY
		THEN OPDSPIX_.MULMIX
		ELSE
		OPDSPIX_.MULDPIX;	!MULTIPLY BY MEMORY
		CGOPGEN()		!GENERATE MULTIPLY
	END;
END
WHILE .CN[0] NEQ .A2NODE;
END;





GLOBAL ROUTINE CGETVAL=
%(*****************************************************************
	ROUTINE TO GET THE VALUE ASSOCIATED WITH A GIVEN NODE WITHIN
	REACH OF ONE INSTRUCTION
	CALLED WITH THE GLOBAL TREEPTR POINTING TO THE NODE TO
	 BE EVALUATED
********************************************************************)%
BEGIN
	REGISTER PEXPRNODE CNODE;		!PTR TO NODE BEING PROCESSED

	CNODE_.TREEPTR;


	%(*****DISPATCH TO A ROUTINE TO PROCESS NODES OF THIS OPERATOR CLASS*****)%

	CASE .CNODE[OPRCLS] OF SET

		%(****FOR BOOLEANS****)%
		CGVBOOL();

		%(****FOR DATA ITEMS****)%
		RETURN;

		%(*****FOR RELATIONALS*****)%
		BEGIN

			%(***INIT VAL TO TRUE***)%
			REGFORCOMP_GETTAC(CNODE);
			OPDSPIX_SETLOGIX(CNODE,TRUE);
			CGOPGEN();

			%(***GENERATE CODE TO SKIP ON RELATIONAL TRUE***)%
			CGREL1(TRUE);

			%(***GENERATE 1 INSTR TO SET VAL FALSE***)%
			TREEPTR_.CNODE;
			REGFORCOMP_GETTAC(CNODE);
			OPDSPIX_SETLOGIX(CNODE,FALSE);
			CGOPGEN();
		END;


		%(*****FOR FUNCTION CALLS*****)%
		CGSBPRGM(.CNODE[ARG2PTR],.CNODE[ARG1PTR]);


		%(*****FOR ARITHMETIC OPERATIONS*****)%

		BEGIN
			%(***GET RID OF "A2NEGFLG" BY - 
				A+(-B)= A-B
				A-(-B)= A+B
				A*(-B)= (-A)*B
				A/(-B)= (-A)/B
			*******)%
			IF .CNODE[A2NEGFLG]
			THEN
			BEGIN
				IF ADDORSUB(CNODE)
				THEN
				BEGIN
					CMPLSP(CNODE);
					CNODE[A2NEGFLG]_0;
				END
				ELSE
				IF MULORDIV(CNODE)
				THEN
				BEGIN
					CNODE[A1NEGFLG]_NOT .CNODE[A1NEGFLG];
					CNODE[A2NEGFLG]_0;
				END;
			END;

			%(***IF A1NEGFLG IS NOW SET, AND ARG1 IS AN EXPRESSION, TRY TO
				PROPAGATE THE NEGATIVE OVER ARG1 (SO THAT WONT HAVE TO
				COMPUTE ARG1 AND THEN NEGATE IT)
			****)%
			IF .CNODE[A1NEGFLG] AND NOT .CNODE[A1VALFLG]
			THEN
			BEGIN
				IF PROPNEG(.CNODE[ARG1PTR])
				THEN CNODE[A1NEGFLG]_0;
			END;



			%(***EVALUATE THE ARGS UNDER THIS NODE - AND SET UP GLOBALS A1NODE AND A2NODE***)%
			CGARGEVAL();

			%(***GET ARG1 INTO LOC FOR COMPUTATION***)%
			REGFORCOMP_GETTAC(CNODE);
			OPDSPIX_GETA1OPIX(CNODE,A1NODE);
			CGOPGEN();

			%(***USE OPGENTABLE TO EVALUATE PARENT***)%
			OPDSPIX_ARITHOPIX(CNODE);
			CGOPGEN();
		END;


		%(*****FOR TYPE CONVERSION*****)%
		BEGIN
			%(***EVALUATE THE SINGLE ARGUMENT OF THIS NODE***)%
			IF NOT .CNODE[A2VALFLG]
			THEN
			%(**UNLESS ARG IS ALREADY EVALUATED***)%
			BEGIN
				TREEPTR_.CNODE[ARG2PTR];
				CGETVAL();
			END;

			%(***UNLESS NO CODE NEEDS TO BE GENERATED FOR THE "CONVERSION",
				GET THE VAL OF THE SUBNODE INTO A REG AND CONVERT IT***)%
			IF NOT NOCNV(CNODE)
			THEN
			BEGIN
				REGFORCOMP_GETTAC(CNODE);
				%(***GENERATE CODE TO GET ARG2 INTO A REGISTER***)%
				TREEPTR_.CNODE;
				A1NODE_.CNODE[ARG2PTR];
				OPDSPIX_GETA2OPIX(CNODE,A1NODE);
				CGOPGEN();

				%(***GENERATE CODE TO CONVERT THE VALUE***)%
				A2NODE_.CNODE[ARG2PTR];
				OPDSPIX_TPCNVIX(CNODE,A1NODE);
				CGOPGEN();
			END;

		END;


		%(****FOR AN ARRAY REFERENCE*******)%
		BEGIN
			%(***EVALUATE THE EXPRESSION FOR THE ADDRESS CALC***)%
			IF NOT .CNODE[A2VALFLG]
			THEN
			BEGIN
				TREEPTR_.CNODE[ARG2PTR];
				CGETVAL();
			END;

			%(***GET THE PART OF THE ADDRESS WHICH MUST BE COMPUTED AT RUN TIME
				INTO THE INDEX-REG USED IN ACCESSING THE VAL OF CNODE***)%
			IF .CNODE[ARG2PTR] NEQ 0	!UNLESS THE SUBSCRPIT CALC WAS
							!ENTIRELY A COMPILE-TIME CONSTANT
			THEN
			BEGIN
				REGFORCOMP_GETTXF(CNODE);
				A1NODE_.CNODE[ARG2PTR];
				TREEPTR_.CNODE;
				OPDSPIX_GETA2OPIX(CNODE,A1NODE);
				CGOPGEN();
			END;

		END;

		%(***FOR A COMMON SUBEXPRESSION - SHOULD NEVER WALK DOWN HERE***)%
		RETURN;

		%(***FOR NEG/NOT NODE (A FEW OF THEM WILL BE LEFT)***)%
		BEGIN
			%(***IF ARG IS NOT A SIMPLE VAR, GENERATE CODE TO EVAL IT***)%
			IF NOT .CNODE[A2VALFLG]
			THEN
			BEGIN
				TREEPTR_.CNODE[ARG2PTR];
				CGETVAL();
			END;

			TREEPTR_.CNODE;
			REGFORCOMP_GETTAC(CNODE);
			A1NODE_.CNODE[ARG2PTR];
			A2NODE_.CNODE[ARG2PTR];

			%(***IF A2NEG,A2NOT,OR A2SAME FLAG IS SET, USE GETA2OPIX TO
				GET THE ARG  INTO REGFORCOMP***)%
			IF .CNODE[A2NEGFLG] OR .CNODE[A2NOTFLG] OR .CNODE[A2SAMEFLG]
			THEN
			BEGIN
				OPDSPIX_GETA2OPIX(CNODE,A1NODE);
				CGOPGEN();

				OPDSPIX_NEGNOT1IX(CNODE);
				CGOPGEN();
			END
			ELSE
			BEGIN
				OPDSPIX_NEGNOT2IX(CNODE);
				CGOPGEN();
			END;
		END;

		%(***FOR SPECIAL OPERATORS INTRODUCED BY PHASE 2 SKEL***)%
		BEGIN
			%(***COMPUTE THE VAL OF ARG1*******)%
			IF NOT .CNODE[A1VALFLG]
			THEN
			BEGIN
				TREEPTR_.CNODE[ARG1PTR];
				CGETVAL();
			END;


			TREEPTR_.CNODE;
			A1NODE_.CNODE[ARG1PTR];
			REGFORCOMP_GETTAC(CNODE);

			%(***GET ARG1 INTO THE REG FOR COMPUTATION OF THIS NODE***)%
			OPDSPIX_GETA1OPIX(CNODE,A1NODE);
			CGOPGEN();

			%(***GENERATE CODE TO PERFORM THE OPERATION*****)%
			IF .CNODE[OPERSP] NEQ EXPCIOP THEN
			BEGIN
				OPDSPIX_SPECOPIX(CNODE);
				CGOPGEN()
			END
			ELSE

			%(***GENERATE CODE FOR IN LINE EXPONENTIATION
			 ***)%
			BEGIN
				TREEPTR_.CNODE;
				A2NODE_.CNODE[ARG2PTR];
				CGEXCIOP()
			END;

		END;

		%(***FOR FIELDREF - NOT IMPLEMENTED IN RELEASE 1 OF FORTRAN***)%
		BEGIN
		END;

		%(***FOR STORECLS - THESE ARE NODES TO CAUSE A PTR
			TO AN ARRAY ELEMENT OR THE CONTENTS OF AN ARRAY ELEMENT
			TO BE STORED IN A TEMPORARY
		*********)%
		BEGIN
			%(***EVALUATE THE EXPRESSION TO BE STORED***)%
			TREEPTR_.CNODE[ARG2PTR];
			CGETVAL();

			TREEPTR_.CNODE;
			A2NODE_.CNODE[ARG2PTR];
			REGFORCOMP_GETTAC(CNODE);
			OPDSPIX_STCLSOPIX(CNODE);
			CGOPGEN();
		END;

		%(***FOR REGCONTENTS NODE - SHOULD RARELY WALK DOWN ON THEM***)%
		BEGIN END;

		%(***FOR LABOP - SHOULD ONLY GET HERE FOR LABELS USED AS ARGS***)%
		BEGIN END;

		%(***FOR STATEMENT - SHOULD NEVER GET HERE*********)%
		CGERR();

		%(***FOR AN IOLIST ELEMENT - SHOULD NEVER GET HERE***)%
		CGERR();

		%(***FOR AN IN-LINE FUNCTION*****************)%
		CGILF();

		TES;

	%(****IF FLAG IS SET IN CNODE INDICATING THAT THE VALUE OF THIS
		NODE MUST BE STORED AFTER IT IS COMPUTED, DO SO***)%
	IF .CNODE[STOREFLG]
	THEN
	BEGIN
		TREEPTR_.CNODE;
		REGFORCOMP_(IF .CNODE[OPRCLS] EQL FNCALL
			THEN RETREG^23		!FOR FN CALL STORE RETURN REG
			ELSE GETTAC(CNODE));	!OTHERWISE, THE TARGET REG
		OPDSPIX_STOROPIX(CNODE);
		CGOPGEN();
	END;

END;

GLOBAL ROUTINE CGOPGEN = 
%(**********************************************************************
	THIS ROUTINE IS CALLED TO GENERATE THE CODE SPECIFIED BY
	SOME SPECIFIED OPGENTABLE ENTRY FOR SOME SPECIFIED NODE

	CALLED WITH THE GLOBALS
	TREEPTR - PTR TO THE NODE FOR WHICH CODE IS BEING GENERATED
	A1NODE - PTR TO THE 1ST ARG NODE UNDER THAT NODE
	A2NODE - PTR TO THE 2ND ARG NODE UNDER THAT NODE
	OPDSPIX - CONTAINS PTR INTO THE OPGENTABLE-DISPATCH-TABLE
		FOR THE OPGENTABLE ENTRY TO BE USED IN INTERPRETING
		THIS NODE
	REGFORCOMP - BITS 9-12 OF THIS WD IDICATE REGISTER (OR REGISTER-PAIR) TO BE USED
			IN THE COMPUTATION FOR WHICH CODE IS BEING GENERATED


**********************************************************************)%

BEGIN
	MAP BASE PSYMPTR;			!PTR TO SYMBOL TABLE ENTRY
	REGISTER OPGENTRY OPGENPTR;		!PTR TO WD IN OPGENTABLE BEING PROCESSES
	OWN PEXPRNODE REFNODE;			!INDICATES WHICH EXPRESSION NODE
						! SPECIFIES THE MEMREF FIELD TO BE USED
						! (MAY BE ARG1, ARG2, OR PARENT)

	%(****DEFINE ROUTINES TO SET UP THE MEMREF FIELD CORRESPONDING TO A
		NODE*******)%

	%(***FOR A DATA NODE, TARGET FIELD SPECIFIES MEMREF FOR INSTRUCTION,
		PTR TO THE "NODE" ITSELF IS THE SYMBOL-TABLE PTR TO OUTPUT***)%
	ROUTINE MRFDATA=
	BEGIN
		PBOPWD_.PBOPWD+.REFNODE[IDTARGET];
		IF .REFNODE[OPERSP] EQL FORMLVAR	!FOR A FORMAL PARAM
			AND .REFNODE[IDATTRIBUT(NOALLOC)]	! THAT IS NOT EVER COPIED TO A LOCAL
		THEN PSYMPTR_ PBFNOSYM
		ELSE
		PSYMPTR_.REFNODE;
	END;


	%(***FOR AN ARRAYREF NODE, TARGET FIELD SPECIFIES MEMREF FIELD FOR
		INSTRUCTION, "ARG1PTR" UNDER THE NODE PTS TO THE SYMBOL-TABLE ENTRY***)%
	ROUTINE MRFARREF=
	BEGIN
		MAP OBJECTCODE PBOPWD;
		OWN PEXPRNODE ARRSYMENTRY;	!SYMBOL TABLE ENTRY FOR THE ARRAY NAME
		ARRSYMENTRY_.REFNODE[ARG1PTR];
		PBOPWD[OBJADDR]_.PBOPWD[OBJADDR]+.REFNODE[TARGADDR];	!ADD THE ADDRESS+OFFSET
									! FROM THE NODE TO THOSE
								!FROM THE TABLE (SUPPRESS OVFL INTO
								!THE INDEX FIELD)
		PBOPWD[OBJIXF]_.PBOPWD[OBJIXF]+.REFNODE[TARGIXF];	!ADD THE INDEX AND INDIRECT
								! FIELDS FROM THE NODE TO THOSE FROM
								! THE TABLE

		%(***IF THE ARRAY IS A FORMAL, ADDRESS FIELD OF INSTR WILL NOT BE RELOCATED***)%
		IF .ARRSYMENTRY[FORMLFLG]
		THEN PSYMPTR_PBFNOSYM

		%(***OTHERWISE, WILL REFER TO THE SYMBOL TABLES ENTRY FOR THE ARRAY NAME***)%
		ELSE
		PSYMPTR_.ARRSYMENTRY;
	END;

	%(***FOR BOOLEAN,RELATIONAL,ARITHMETIC,FN CALL, TYPECNV, NEG/NOT, AND SPECIAL-CASE
		NODES - THE VALUE MAY BE EITHER IN A REG OR A TEMPORARY.
		IF IN A REG, THAT REG IS MEMREF FIELD AND PSYMPTR FIELD IS  "1".
		IF IN A TEMPORARY, THE TARGET FIELD OF THE NODE PTS TO THE TEMPORARY
		TABLE ENTRY FROM WHICH THE ADDR MUST BE RETRIEVED
		THE PTR TO THE TEMPORARY TABLE ENTRY BECOMES THE PSYMPTR
	*********)%
	ROUTINE MRFEXPR=
	BEGIN
		%(***SET INDEX AND INDIRECT FIELDS OF INSTRUCTION FROM THOSE OF TARGET***)%
		PBOPWD_.PBOPWD+GETTXFI(REFNODE);

		%(***IF THE TARGET-MEMREF IS USING AN AC AS A CORE-LOC***)%
		%(*****THEN THERE IS NO SYMBOLIC REPRESENTATION *****)%
		IF .REFNODE[INREGFLG]
		THEN
		BEGIN
				PBOPWD_.PBOPWD+.REFNODE[TARGTAC];
				PSYMPTR_PBFNOSYM;
		END
		ELSE
		BEGIN
			PSYMPTR_.REFNODE[TARGADDR];
			PBOPWD_.PBOPWD + .PSYMPTR[IDADDR];
		END;
	END;


	%(***FOR A COMMON SUBEXPR NODE - ALWAYS USE THE RIGHT HALF OF THE TARGET
		(EVEN IF INREGFLG IS SET - THIS IS NECESSARY FOR DOUBLE-PREC OPS ON KA10
		 WHERE THE 2ND ARG FOR THE DOUBLE-PREC ROUTINE MUST NOT BE IN A REG)
	*******)%
	ROUTINE MRFCSB=
	BEGIN
		IF .REFNODE[TARGADDR] LEQ #17
		THEN
		BEGIN
			%(***IF RH OF TARGET INDICATES THAT CSB IS ONLY IN A REG***)%
			PBOPWD_.PBOPWD+.REFNODE[TARGADDR];
			PSYMPTR_PBFNOSYM;
		END
		ELSE
		BEGIN
			%(***IF THE CSB HAS BEEN STORED IN A TMP***)%
			PSYMPTR_.REFNODE[TARGADDR];
			PBOPWD_.PBOPWD+.PSYMPTR[IDADDR];
		END
	END;
!**;[337], CGOPGEN @3769, DCE, 30-DEC-75
!**;[337], ROUTINE TO ROUND UP SINGLE PRECISION FROM DOUBLE PRECISION
%[337]%	ROUTINE  KISNGL(X,Y)=
%[337]%	BEGIN
%[337]%		!X IS THE HIGH ORDER KI-10 CNSTANT, Y IS LOW ORDER WORD
%[337]%		REGISTER HI,LOW;
%[337]%		HI _ .X; LOW _ .Y;
%[337]%		IF .HI LSS 0
%[337]%		THEN (HI _ -.HI; LOW _ -.LOW;
%[337]%			IF .LOW NEQ 0 THEN HI _ .HI-1;
%[337]%		     );
%[337]%		IF .LOW<34,1>		!IS ROUNDING NECESSARY?
%[337]%		THEN(
%[337]%			IF .HI NEQ #377777777777
%[337]%			THEN HI _ .HI+1;
%[337]%			HI<26,1> _ 1;	!SET HIGHORDER BIT ON
%[337]%		    );
%[337]%		IF .X LSS 0 THEN HI _ -.HI;	!RESTORING SIGN
%[337]%		.HI		!IS RETURNED
%[337]%	END;

	OPGENPTR_@.OPDSPIX;		!GET AOBJN PTR TO SET OF OPGENTABLE INSTRUCTIONS

	%(****IF THIS PTR IS 0, NO INSTRUCTIONS NEED TO BE GENERATED***)%
	IF .OPGENPTR EQL 0
	THEN RETURN
	%(***IF THIS PTR IS 1 - THEN HAVE AN ILLEGAL COMBINATION OF FLAGS***)%
	ELSE 
	IF .OPGENPTR EQL 1
	THEN
	BEGIN
		CGERR();
		RETURN;
	END;


	%(*****REPEAT THE FOLLOWING BLOCK FOR ALL INSTRUCTIONS TO BE OUTPUT*******)%
	%(********CT OF INSTRUCTIONS TO BE OUTPUT IS IN LEFT HALF OF THE
			PTR OPGENPTR*********)%
	DO
	BEGIN
		PBOPWD_.OPGENPTR[PATTERN];
		%(***IF THE PATTERN WD DOES NOT SPECIFY THE REGISTER
			FIELD TO BE USED, THEN THE GLOBAL "REGFORCOMP"
			SPECIFIES A FIELD-VAL TO BE ADDED IN TO THAT SPECIFIED
			BY THE PATTERN WD*****)%
		IF .OPGENPTR[REGSPEC] NEQ FRPTN
		THEN
		PBOPWD_.PBOPWD+.REGFORCOMP;


		%(***DETERMINE THE MEMREF FIELD  (IE BITS 13-35) OF THE INSTRUCTION *****)%

		CASE .OPGENPTR[MEMSPEC] OF SET
		%(**0 MEANS USE FIELD IN WD 0 OF OPGENTABLE ENTRY***)%
		PSYMPTR_PBFNOSYM;
		%(***1 MEANS USE THE "REGFORCOMP" AS A MEMORY ADDRESS***)%
		BEGIN
			PBOPWD_.PBOPWD+(.REGFORCOMP^(-23));
			PSYMPTR_PBFNOSYM;
		END;

		%(***2 MEANS USE THE IMPLICIT FN-NAME POINTED TO BY TREEPTR***)%
		BEGIN
			PSYMPTR_PBFIMFN;
			PBOPWD_.PBOPWD+.TREEPTR;
		END;

		%(***3 MEANS USE THE IMPLICIT FN-NAME POINTED TO BY THE PATTERN WD***)%
		PSYMPTR_PBFIMFN;

		%(***4 MEANS USE THE IMPLICIT FN NAME POINTED TO BY THE PATTERN WD INDEXED
			BY THE "REGFORCOMP" - (E.G. A DIFFERENT LIBRARY ROUTINE IS USED
			BY THE "REGFORCOMP" - (E.G. THE LIBRARY ROUTINE TO BE USED FOR
			A DOUBLE-PREC OP DEPENDS ON THE REG IN WHICH THE ARG WAS LEFT***)%
		BEGIN
			PBOPWD_.PBOPWD+.REGFORCOMP^(-23);
			PSYMPTR_PBFIMFN;
		END;

		%(***5 MEANS USE A1NODE IN IMMEDIATE MODE - EITHER AS AN IMMED CONSTANT OR
			IF ITS A "REGCONTENTS", THEN AS 0(R)****)%
		BEGIN
			PSYMPTR_PBFNOSYM;

			IF .A1NODE[OPR1] EQL CONSTFL
			THEN
			PBOPWD_.PBOPWD +
				(IF .A1NODE[VALTP1] EQL INTEG1
				THEN (.A1NODE[CONST2] AND #777777)
	!**;[337], CGOPGEN @3838, DCE,30-DEC-75
	!**;[337], ROUND UP REAL IMMEDIATE CONSTANT BEFORE LISTING IT
	%[337]%			ELSE  (KISNGL(.A1NODE[CONST1],.A1NODE[CONST2])^(-18)))
			ELSE
			IF .A1NODE[OPRCLS] EQL REGCONTENTS
			THEN
			PBOPWD_.PBOPWD+.A1NODE[TARGTAC]^18;
		END;

		%(***6 MEANS USE A2NODE IN IMMEDIATE MODE - EITHER AS AN IMMED CONSTANT OR
			IF ITS A "REGCONTENTS", THEN AS 0(R)****)%
		BEGIN
			PSYMPTR_PBFNOSYM;

			IF .A2NODE[OPR1] EQL CONSTFL
			THEN
			PBOPWD_.PBOPWD +
				(IF .A2NODE[VALTP1] EQL INTEG1
				THEN (.A2NODE[CONST2] AND #777777)
				ELSE  (.A2NODE[CONST1]^(-18)))
			ELSE
			IF .A2NODE[OPRCLS] EQL REGCONTENTS
			THEN
			PBOPWD_.PBOPWD+.A2NODE[TARGTAC]^18;
		END;

		%(***7 MEANS USE THE NEG OF THE IMMED CNST A1NODE***)%
		BEGIN
			PBOPWD_.PBOPWD +
			(IF .A1NODE[VALTP1] EQL INTEG1
			THEN (-.A1NODE[CONST2]) AND #777777
			ELSE (-.A1NODE[CONST1])^(-18) );
			PSYMPTR_PBFNOSYM;
		END;

		%(***8 (#10) MEANS USE THE NEG OF THE IMMED CNST A2NODE***)%
		BEGIN
			PBOPWD_.PBOPWD +
			(IF .A2NODE[VALTP1] EQL INTEG1
			THEN (-.A2NODE[CONST2]) AND #777777
			ELSE (-.A2NODE[CONST1])^(-18) );
			PSYMPTR_PBFNOSYM;
		END;


		%(***9 (#11) MEANS USE THE "ARG2PTR" FIELD FROM THE PARENT***)%
		BEGIN
			PBOPWD_.PBOPWD+.TREEPTR[ARG2PTR];
			PSYMPTR_PBFNOSYM;
		END;

		%(***10 (#12) MEANS USE THE NEG OF THE ARG2PTR FIELD OF THE PARENT***)%
		BEGIN
			PBOPWD_.PBOPWD+(-.TREEPTR[ARG2PTR] AND #777777);
			PSYMPTR_PBFNOSYM;
		END;

		%(***11 (#13) MEANS USE 2**(VAL OF ARG2PTR) MINUS 1. (THIS IS USED
			FOR P2DIV)****)%
		BEGIN
			PBOPWD_.PBOPWD+(( (1^.TREEPTR[ARG2PTR]) - 1) AND #777777);
			PSYMPTR_PBFNOSYM;
		END;


		%(***12 (#14) MEANS USE THE LABEL SPECIFIED BY A1LABEL***)%
		BEGIN
			PBOPWD_.PBOPWD+.A1LABEL;
			PSYMPTR_PBFLABREF;
		END;

		%(***13 (#15) MEANS USE THE LABEL SPECIFIED BY A2LABEL***)%
		BEGIN
			PBOPWD_.PBOPWD+.A2LABEL;
			PSYMPTR_PBFLABREF;
		END;

		%(***14 (#16) MEANS USE THE LABEL SPECIFIED BY A3LABEL***)%
		BEGIN
			PBOPWD_.PBOPWD+.A3LABEL;
			PSYMPTR_PBFLABREF;
		END;
		%(***15 (#17) MEANS USE THE VALUE IN THE GLOBAL C1H, NO SYMBOLIC REPRESENTATION***)%
		BEGIN
			PBOPWD_.PBOPWD+.C1H;
			PSYMPTR_PBFNOSYM;
		END;


		%(***16 (#20) MEANS USE THE TEMPORARY POINTED TO BY THE TARGET WD OF THE PARENT -
			IGNORE THE INDIRECT AND INDEX BITS IN THAT TARGET WD***)%
		BEGIN
			PSYMPTR_.TREEPTR[TARGADDR];
			PBOPWD_.PBOPWD+.PSYMPTR[IDADDR];
		END;

		%(***17 (#21) MEANS USE MEMREF FIELD FROM A1NODE***)%
		REFNODE_.A1NODE;
		%(***18 (#22) MEANS USE MEMREF FIELD FROM A2NODE**)%
		REFNODE_.A2NODE;
		%(***19 (#23) MEANS USE MEMREF FIELD FROM PARENT NODE (IE NODE PTED TO BY TREEPTR)***)%
		REFNODE_.TREEPTR

		TES;

		%(***IF THE MEMREF FIELD MUST BE RETRIEVED FROM THE NODE SPECIFIED BY
			REFNODE, DO SO***)%

		IF .OPGENPTR[MEMSPEC] GEQ FROMA1
		THEN
		BEGIN
			%(***IF REFNODE IS A TYPE-CONVERSION NODE THAT GENERATES NO CODE (IS ONLY
				TO SPECIFY VALTYPE), MOVE DOWN TO THE ARG UNDER REFNODE***)%
			IF .REFNODE[OPRCLS] EQL TYPECNV
			THEN
			BEGIN
				IF NOCNV(REFNODE)
				THEN
				BEGIN
					REFNODE_.REFNODE[ARG2PTR];
					WHILE .REFNODE[OPRCLS] EQL TYPECNV AND NOCNV(REFNODE)
					DO REFNODE_.REFNODE[ARG2PTR];
				END;
			END;

			CASE .REFNODE[OPRCLS] OF SET
			MRFEXPR();		!GET MEMREF FROM A BOOLEAN NODE
			MRFDATA();		! FROM A SYMBOL TABLES ENTRY
			MRFEXPR();		! FROM A RELATIONAL
			MRFEXPR();		! FROM A FN CAL
			MRFEXPR();		! FROM AN ARITH NODE
			MRFEXPR();		! FROM A TYPECNV NODE
			MRFARREF();		! FROM AN ARRAYREF NODE
			MRFCSB();		! FROM A COMMON SUB NODE
			MRFEXPR();		! FROM A NEG/NOT NODE
			MRFEXPR();		! FROM A SPECIAL-CASE NODE
			BEGIN END;		! FROM A FIELD-REF NODE (NOT IMPLEMENTED
						! IN RELEASE 1)
			MRFEXPR();		! FROM A STORECLS NODE
			( PBOPWD_.PBOPWD+.REFNODE[TARGTAC];
			 PSYMPTR_PBFNOSYM);	!FROM A REGCONTENTS NODE
			CGERR();		!REFNODE SHOULD NEVER BE A LABEL
			CGERR();		!REFNODE SHOULD NEVER BE A STMNT
			CGERR();		!REFNODE SHOULD NEVER BE AN IOLIST ELEM
			MRFEXPR();		!FOR AN IN-LINE-FN
			TES;
		END;



		%(****OUTPUT THE INSTR FORMED TO THE PEEPHOLE BUFFER***)%
		OBUFF();


		%(***INCREMENT AOBJN PTR INTO THE OPGEN TABLE****)%
		OPGENPTR_.OPGENPTR+1;
		OPGENPTR_.OPGENPTR+AOBINCR;	!ADD 1,,1

	END
	WHILE .OPGENPTR LSS 0;

END;


GLOBAL ROUTINE CGARGEVAL=
%(************************************************************
	ROUTINE TO EVALUATE THE 2 ARGUMENT NODES OF SOME EXPRESSION
	NODE AND PUT THE VAL OF THE 1ST INTO THE LOC SPECIFIED FOR THE
	COMPUTATION
************************************************************)%

BEGIN
	REGISTER PEXPRNODE CNODE;			!PTR TO PARENT NODE
	CNODE_.TREEPTR;

	IF NOT .CNODE[RVRSFLG]

	THEN
	%(*****IF 1ST ARG SHOULD BE EVALUATED FIRST, EVALUATE IT******)%
	BEGIN
		IF NOT .CNODE[A1VALFLG]

		THEN
		%(****UNLESS THIS ARG IS ALREADY EVALUATED SOMEWHERE EVALUATE IT*****)%
		BEGIN
			TREEPTR_.CNODE[ARG1PTR];
			CGETVAL();
		END
	END;

	%(**************EVALUATE 2ND ARG********************)%
	IF NOT .CNODE[A2VALFLG]

	THEN
	%(*****UNLESS ARG2 IS ALREADY EVALUATED SOMEWHERE OR IS
		AN IMMED CONSTANT, EVALUATE IT**********)%
	BEGIN
		IF (TREEPTR_.CNODE[ARG2PTR]) NEQ 0 THEN
		CGETVAL();
	END;

	IF .CNODE[RVRSFLG]

	THEN
	%(*****IF ARG1 SHOULD BE EVALUATED 2ND, EVALUATE IT******)%
	BEGIN
		IF NOT .CNODE[A1VALFLG]

		THEN
		%(****UNLESS THIS ARG IS ALREADY EVALUATED SOMEWHERE  EVALUATE IT*****)%
		BEGIN
			TREEPTR_.CNODE[ARG1PTR];
			CGETVAL();
		END
	END;


	%(********SET UP GLOBALS FOR OPGENTABLE INTERPRETATION********)%
	TREEPTR_.CNODE;				!TREEPTR MAY HAVE BEEN DESTROYED BY CGETVAL
	A1NODE_.CNODE[ARG1PTR];
	A2NODE_.CNODE[ARG2PTR];



END;




GLOBAL ROUTINE CGILF=
%(***************************************************************************
	ROUTINE TO GENERATE CODE FOR IN-LINE FUNCTIONS.
	CALLED WITH TREEPTR POINTING TO THE NODE FOR THE IN-LINE-FUNCTION-CALL
***************************************************************************)%
BEGIN
	LOCAL PEXPRNODE CNODE;
	LOCAL PEXPRNODE ARG1NODE:ARG2NODE;

	%(***EVALUATE ARGUMENTS***)%

	CGARGEVAL();

	%(***SET UP THE GLOBALS USED BY CGOPGEN (CODE TABLE DRIVER)***)%

	CNODE_.TREEPTR;
	A1NODE_.CNODE[ARG1PTR];
	A2NODE_.CNODE[ARG2PTR];
	TREEPTR_.CNODE;
	REGFORCOMP_GETTAC(CNODE);

	%(***COMPLETE CODE GENERATION FOR CMPLX***)%

	IF .CNODE[OPERSP] EQL CMPLXFN THEN
	BEGIN
		OPDSPIX_GETA1OPIX(CNODE,A1NODE);
		CGOPGEN();
		REGFORCOMP_.REGFORCOMP+1^23;
		SWAPARGS(CNODE);
		A1NODE_.CNODE[ARG1PTR];
		OPDSPIX_GETA1OPIX(CNODE,A1NODE);
		RETURN CGOPGEN()
	END;

	%(***FOR ABS,IABS, AND SIGN - UNLESS A1SAMEFLG OR A1IMMEDFLG IS SET,
		WILL PICK UP ARG1 BY A MOVM. HENCE DO NOT GET IT INTO A RE