Trailing-Edge
-
PDP-10 Archives
-
BB-4157E-BM
-
fortran-compiler/p2s1.bli
There are 26 other files named p2s1.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,1981 BY DIGITAL EQUIPMENT CORPORATION
!AUTHOR: S. MURPHY/JNG/DCE/TFV
MODULE P2S1(SREG=#17,VREG=#15,FREG=#16,DREGS=4,RESERVE(0,1,2,3),GLOROUTINES) =
BEGIN
SWITCHES NOLIST;
REQUIRE FIRST.BLI;
REQUIRE TABLES.BLI;
REQUIRE OPTMAC.BLI; ![671]
SWITCHES LIST;
GLOBAL BIND P2S1V = 6^24 + 0^18 + 64; ! Version Date: 17-Jul-81
%(
***** Begin Revision History *****
57 ----- ----- DO NOT CHECK FOR EXPONEN INVOLVING A LOOP
INDEX UNTIL AFTER IN LINE EXPONENS HAVE BEEN
DETECTED (SO THAT I**2 DOESNT CAUSE THE LP INDEX
TO BE MATERIALIZED)
58 ----- ----- FIX TYPO IN "P2SKFN". WHEN REMOVE A NEG FROM
UNDER AN IN-LINE FN, WHEN
GETTING PTR TO NODE TO SET PARENT PTR, SHOULD
LOOK AT "CNODE[ARG1PTR]", (NOT ARGNODE[ARG1PTR])
59 ----- ----- IN "ARSKOPT", USE "KEXPIX" TO FOLD EXPONEN OF CONSTS
(RATHER THAN SQROP,CUBOP,P4OP)
60 434 19211 CHECK IF FN PARAM IS DO LOOP INDEX AFTER CONST
FOLDING IN CASE I+0 TYPE CONSTRUCTION., (JNG)
61 445 19632 REDUCE CHANCE OF STACK OVERFLOW BY CUTTING
DOWN NUMBER OF LOCALS FOR P2SKARITH, (DCE)
62 671 NVT WHEN SWAPPING ARGS, SWAP DEF PTS TOO, (DCE)
***** Begin Version 6 *****
63 761 TFV 1-Mar-80 -----
Remove KA10FLG and use /GFLOATING when rounding DP to SP
64 1031 TFV 25-Nov-80 ------
When folding relationals, chose low or high word of each constant
based on VALTP1 since octals are not converted to real under GFLOATING
***** End Revision History *****
)%
! CREATE A POINTER TO A STACK REFERENCE -
! HENCE DEFINE 'FREG1' EQUAL TO FREG
EXTERNAL
CANONICALIZE,CGERR,MAKEPR,C1H,C1L,C2H,C2L,COPRIX,
%[761]% KBOOLBASE,KTYPCB,KTYPCG,KARIIB,KARIGB,CNSTCM,DNEGCNST,TBLSEARCH,
SKERR;
FORWARD
P2SKBL(1),BLSKOPT(1), P2SKIGNORE(1),P2SKREL(1),RELSKOPT(1), P2SKFN(1), P2SKARITH(1),ARSKOPT(1),
P2SKLTP(1), P2SKLARR(1),P2SKNEGNOT(1);
EXTERNAL
NEGOFNOT,NOTOFNEG, BLCMB,
ARCMB,CMBEQLARGS;
EXTERNAL NEGFLG,NOTFLG;
EXTERNAL SETPVAL;
EXTERNAL KDNEGB;
EXTERNAL TAKNEGARG,TAKNOTARG;
EXTERNAL SAVSPACE;
EXTERNAL KSPECB,KSPECG;
%(************************************************************************
INITIAL PASS OF PHASE 2 SKELETON.
THIS PASS OVER AN EXPRESSION TREE PERFORMS THE FOLLOWING:
1. ELIMINATES NEG AND NOT NODES, FORCING THEM
DOWN TO THE BOTTOM IF POSSIBLE. IN DOING THIS
THE FOLLOWING GLOBALS ARE USED.
NEGFLG - IF THIS FLAG IS TRUE WHEN THE ROUTINE
IS CALLED FOR A GIVEN NODE, A NEG IS
TO BE FORCED DOWN FROM ABOVE.
THIS FLAG IS RETURNED TRUE IF THE
PARENT ABOVE THIS NODE MUST HANDLE
NEGATION FOR THIS NODE.
NOTFLG - LIKE NEGFLG EXCEPT INDICATING THAT A
NOT IS TO BE FORCED DOWN (OR BACK UP).
2. ELIMINATES THE SUBTRACT OPERATOR, CHANGING IT TO ADD
AND PROPAGATING THE NEG DOWN OVER THE 2ND ARG
3. CHECKS FOR ANY OPERATIONS WHICH ARE PERFORMED ON
CONSTANTS AND MAY BE PERFORMED AT COMPILE TIME.
PERFORMS SUCH OPERATIONS AND REPLACES THEIR ENTRIES
IN THE EXPRESSION TREE BY THE RESULTANT CONSTANT.
CREATES CONSTANT TABLE ENTRIES FOR THESE NEW
CONSTANTS.
4. DETECTS MULTIPLICATION/DIVISION BY A CONSTANT
POWER OF 2 AND CHANGES THE NODE TO P2MUL.
DETECTS MULTIPLICATION BY A POWER OF 2 PLUS 1.
5. DETECTS EXPONENTIATION TO A SMALL (2 OR 3) CONSTANT INTEGER
POWER.
6. N-ARY NODES ARE PUT INTO CANONICAL ORDER.
THIS PASS IS PERFORMED BEFORE COMMON SUBEXPRESSION ELIMINATION.
IT IS PERFORMED BEFORE PHASE 2 WHEN PHASE 2 IS PRESENT
HAVE A ROUTINE CORRESPONDING TO EACH OPERATOR CLASS. TO PROCESS
A GIVEN NODE, DISPATCH TO THE ROUTINE CORRESPONDING TO ITS
OPERATOR CLASS, VIA THE DISPATCH TABLE "P2SKL1DISP".
THESE ROUTINES ARE CALLED WITH THE ARGUMENT
CNODE - A POINTER TO THE NODE IN THE TREE TO BE
PROCESSED.
THEY EACH RETURN A POINTER TO THE NODE TO REPLACE CNODE (THIS
WILL BE CNODE ITSELF UNLESS CONSTANT ELIMINATION OR NEG/NOT
PROPOGATION HAS BEEN PERFORMED).
************************************************************************)%
%(******DEFINE THE DISPATCH TABLE FOR PHASE 2 SKELETON - HAVE A ROUTINE FOR EACH OPERATOR CLASS***)%
BIND DMYXXX = PLIT (
P2SKL1DISP GLOBALLY NAMES
P2SKBL,
P2SKIGNORE, !SHOULD GET HERE VERY RARELY (VALFLG IS
! USUALLY SET AND CHECKED)
P2SKREL,
P2SKFN,
P2SKARITH,
P2SKLTP,
P2SKLARR,
P2SKIGNORE, !COMMON SUBEXPR
P2SKNEGNOT, !NEG/NOT
P2SKIGNORE, !SPECIAL OPS (P2MUL ETC)
P2SKIGNORE, !FIELDREF (NOT IN RELEASE 1)
P2SKIGNORE, !STORECLS
P2SKIGNORE, !REGCONTENTS
P2SKIGNORE, !LABEL
P2SKIGNORE, !STATEMENT
P2SKIGNORE, !IOLSCLS
P2SKIGNORE); !IN-LINE-FN (SINCE THESE ARE INSERTED IN P2S
! SHOULD NOT ENCOUNTER THEM
GLOBAL ROUTINE P2SKBL(CNODE)=
%(*** INITIAL PASS OF PHASE 2 SKELETON FOR A BOOLEAN
***)%
BEGIN
MAP PEXPRNODE CNODE;
LOCAL PEXPRNODE ARG1NODE;
LOCAL PEXPRNODE ARG2NODE;
LOCAL PRVNEGFLG,ARGNOTFLG;
DEBGNODETST(CNODE); !FOR DEBUGGING ONLY
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
%(***
FOR NEG/NOT ELIMINATION.
CANNOT FORCE A NEG DOWN ACROSS THIS NODE.
FORCE DOWN A NOT BY:
NOT(A AND B)=(NOT A) OR (NOT B)
NOT(A OR B)=(NOT A) AND (NOT B)
NOT(A XOR B)=A EQV B
NOT(A EQV B)=A XOR B
***)%
PRVNEGFLG_.NEGFLG;
ARGNOTFLG_.NOTFLG;
IF.NOTFLG
THEN
BEGIN
%(***SET OPERSP TO OR FROM AND, AND FROM OR EQV
FROM XOR, XOR FROM EQV ***)%
CNODE[BOPRFLG]_NOT.CNODE[BOPRFLG];
IF .CNODE[BOOLCLS] NEQ ANDORCLS
THEN
ARGNOTFLG_FALSE;
END;
%(********PROCESS 1ST ARG ********)%
%(***IF ARG IS A LEAF, DO NOT WALK DOWN THERE***)%
IF .CNODE[A1VALFLG]
THEN
BEGIN
IF .ARGNOTFLG THEN CNODE[A1NOTFLG]_1;
END
ELSE
BEGIN
NEGFLG_FALSE;
NOTFLG_.ARGNOTFLG;
ARG1NODE_(.P2SKL1DISP[.ARG1NODE[OPRCLS]])(.ARG1NODE);
%(***IF NEG OR NOT WAS PROPAGATED UP FROM ARG1, SET
THE FLAGS IN CNODE***)%
CNODE[A1NEGFLG]_.NEGFLG<0,1>;
CNODE[A1NOTFLG]_.NOTFLG<0,1>;
END;
%(***IF ARG1 IS A CONSTANT (OR WAS COLLAPSED INTO INTO A CONSTANT BY THE
WALK OVER IT) AND A1NOTFLG IS SET, PERFORM THE 'NOT' OPERATION ***)%
IF .ARG1NODE[OPR1] EQL CONSTFL
THEN
BEGIN
IF .CNODE[A1NOTFLG]
THEN
BEGIN
ARG1NODE_NOTCNST(ARG1NODE);
CNODE[A1NOTFLG]_0;
END
END;
CNODE[ARG1PTR]_.ARG1NODE;
%(*******PROCESS 2ND ARG*******)%
%(***IF ARG IS A LEAF, DO NOT WALK DOWN THERE***)%
IF .CNODE[A2VALFLG]
THEN
BEGIN
IF .ARGNOTFLG THEN CNODE[A2NOTFLG]_1;
END
ELSE
%(***FOR ARG2 NOT A LEAF (OR COMMON SUBEXPR)***)%
BEGIN
NEGFLG_FALSE;
NOTFLG_.ARGNOTFLG;
ARG2NODE_(.P2SKL1DISP[.ARG2NODE[OPRCLS]])(.ARG2NODE);
CNODE[A2NEGFLG]_.NEGFLG<0,1>;
CNODE[A2NOTFLG]_.NOTFLG<0,1>;
END;
%(***IF ARG2 IS A CONSTANT (OR WAS COLLAPSED INTO ONE), PERFORM THE 'NOT'
OPERATION ON IT IF NECESSARY***)%
IF .ARG2NODE[OPR1] EQL CONSTFL
THEN
BEGIN
IF .CNODE[A2NOTFLG]
THEN
BEGIN
ARG2NODE_NOTCNST(ARG2NODE);
CNODE[A2NOTFLG]_0;
END;
END;
CNODE[ARG2PTR]_.ARG2NODE;
NEGFLG_.PRVNEGFLG;
NOTFLG_FALSE;
%(***CHECK FOR OPERATIONS ON CONSTANTS AND OPERATIONS ON 2 IDENTICAL ARGS, FOLD IF CAN***)%
RETURN BLSKOPT(.CNODE);
END;
GLOBAL ROUTINE BLSKOPT(CNODE)=
%(***************************************************************************
ROUTINE TO CHECK WHETHER A BOOLEAN OPERATION HAS ARGUMENTS WHICH
ARE EITHER CONSTANT OR IDENTICAL TO EACHOTHER AND HENCE CAN BE FOLDED.
THE ARG "CNODE" IS A PTR TO THE BOOLEAN NODE TO BE EXAMINED.
IF CNODE CAN BE FOLDED, THIS ROUTINE RETURNS A PTR TO THE
NODE WHICH WILL REPLACE CNODE IN THE EXPRESSION TREE.
OTHERWISE IT RETURNS A PTR TO CNODE
***************************************************************************)%
BEGIN
OWN PEXPRNODE ARG1NODE:ARG2NODE;
MAP PEXPRNODE CNODE;
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
%(***CHECK FOR ARG1 AND ARG2 BOTH CONSTANTS AND IF SO COMPUTE
THE VALUE CORRESPONDING TO CNODE AND REPLACE CNODE BY A CONSTANT
TABLE ENTRY FOR THAT VALUE.
*****)%
IF .ARG1NODE[OPR1] EQL CONSTFL
THEN
BEGIN
IF.ARG2NODE[OPR1] EQL CONSTFL
THEN
BEGIN
%(***GLOBALS USED BY THE ASSEMBLY LANGUAGE ROUTINE THAT
PERFORMS THE OPERATIONS ARE
COPRIX,C1L,C2L*****)%
%(***SET C1L AND C2L TO THE SINGLE-WDS TO BE
OPERATED ON***)%
C1L_IF .ARG1NODE[VALTP1] EQL INTEG1
THEN .ARG1NODE[CONST2]
ELSE .ARG1NODE[CONST1];
C2L_IF .ARG2NODE[VALTP1] EQL INTEG1
THEN .ARG2NODE[CONST2]
ELSE .ARG2NODE[CONST1];
COPRIX_.CNODE[OPERSP] + KBOOLBASE;
%(***FIND THE RESULT OF THIS OPERATION ON THESE
2 CONSTANTS***)%
CNSTCM();
%(***SET VALFLG IN PARENT OF CNODE***)%
SETPVAL(.CNODE);
%(***REPLACE CNODE BY A NEW CONSTANT NODE***)%
CNODE_MAKECNST(LOGICAL,0,.C2L);
END
%(*****CHECK FOR
A AND TRUE = A
A AND FALSE = FALSE
A OR TRUE = TRUE
A OR FALSE = A
A EQV TRUE = A
A XOR TRUE = NOT A
A EQV FALSE = NOT A
A XOR FALSE = A
***************)%
ELSE
%(***IF ARG1 IS TRUE OR FALSE, REPLACE CNODE BY ARG2,
TRUE OR FALSE***)%
CNODE_BLCMB(.CNODE,.ARG1NODE,.ARG2NODE);
END
ELSE
IF .ARG2NODE[OPR1] EQL CONSTFL
THEN
%(***IF ARG2 IS TRUE OR FALSE, REPLACE CNODE BY ARG1,
TRUE, OR FALSE***)%
CNODE_BLCMB(.CNODE,.ARG2NODE,.ARG1NODE)
%(******CHECK FOR
A AND A =A
A AND (NOT A) = FALSE
A OR A = A
A OR (NOT A) = TRUE
A EQV A = TRUE
A EQV (NOT A) = FALSE
A XOR A = FALSE
A XOR (NOT A) = TRUE
****************)%
ELSE
IF .CNODE[ARG1PTR] EQL .CNODE[ARG2PTR]
THEN
%(***IF ARG1 IS EQUAL TO ARG2, THEN TRY TO COLLAPSE CNODE***)%
CNODE_CMBEQLARGS(.CNODE,FALSE);
RETURN CANONICALIZE( .CNODE);
END;
GLOBAL ROUTINE P2SKIGNORE(CNODE)=
%(***************************************************************************
PHASE 2 SKEL ROUTINE FOR A DATA ITEM (CONSTANT OR VARIABLE).
THIS ROUTINE IS ALSO USED FOR REGCONTENTS NODES, LABELS, ETC.
IN GENERAL, DO NOT WALK DOWN TO A DATA NODE BECAUSE THE VALFLG IN THE
PARENT IS SET, AND ALWAYS CHECK THE FLAG BEFORE WALKING DOWN TO A SON.
THIS IS HERE TO KEEP THE COMPILER FROM DYING IN THOSE RARE CASES
WHERE THE VALFLG WAS LEFT UNSET (IT IS USED FOR ELEMENTS ON IOLISTS
WHERE THERE IS NO VALFLG)
.
***************************************************************************)%
BEGIN
RETURN .CNODE
END;
GLOBAL ROUTINE P2SKREL(CNODE)=
%(***
INITIAL PASS OF PHASE 2 SKELETON FOR A RELATIONAL
***)%
BEGIN
MAP PEXPRNODE CNODE;
LOCAL PEXPRNODE ARG1NODE;
LOCAL PEXPRNODE ARG2NODE;
LOCAL PRVNEGFLG;
DEBGNODETST(CNODE); !FOR DEBUGGING ONLY
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
%(***FOR NEG/NOT ELIMINATION -
CAN FORCE DOWN A NOT BY CHANGING THE SENSE OF THE RELATIONAL.
CANNOT FORCE DOWN A NEG.
***)%
IF .NOTFLG
THEN
CNODE[OPERSP]_CMREL(.CNODE[OPERSP]);
PRVNEGFLG_.NEGFLG;
%(***PROCESS FIRST ARG***)%
%(****DO NOT WALK DOWN TO ARG IF IT IS A LEAF OR COMMON SUBEXPR**)%
IF NOT .CNODE[A1VALFLG]
THEN
BEGIN
NEGFLG_FALSE;
NOTFLG_FALSE;
CNODE[ARG1PTR]_(.P2SKL1DISP[.ARG1NODE[OPRCLS]])(.ARG1NODE);
CNODE[A1NEGFLG]_.NEGFLG<0,1>;
CNODE[A1NOTFLG]_.NOTFLG<0,1>;
END;
%(***PROCESS SECOND ARG***)%
IF NOT .CNODE[A2VALFLG]
THEN
BEGIN
NEGFLG_FALSE;
NOTFLG_FALSE;
CNODE[ARG2PTR]_(.P2SKL1DISP[.ARG2NODE[OPRCLS]])(.ARG2NODE);
CNODE[A2NEGFLG]_.NEGFLG<0,1>;
CNODE[A2NOTFLG]_.NOTFLG<0,1>;
END;
%(***SET NEGFLG AND NOTFLG TO THE VALS TO BE PASSED BACK UP TO PARENT***)%
NOTFLG_FALSE;
NEGFLG_.PRVNEGFLG;
%(***CHECK FOR OPS ON CONSTANTS AND OPS ON IDENTICAL ARGS THAT CAN BE FOLDED***)%
RETURN RELSKOPT(.CNODE);
END;
GLOBAL ROUTINE RELSKOPT(CNODE)=
%(***************************************************************************
ROUTINE TO CHECK A RELATIONAL NODE FOR ARGS EQUAL TO CONSTANTS, OR TO EACHOTHER,
AND TO FOLD SUCH A NODE IF IT IS POSSIBLE TO DO SO.
THE ARG "CNODE" POINTS TO THE RELATIONAL NODE TO BE EXAMINED.
IF THE NODE CAN BE FOLDED THEN A PTR TO THE NEW NODE TO REPLACE IT IN
THE TREE IS RETURNED.
OTHERWISE A PTR TO CNODE IS RETURNED.
***************************************************************************)%
BEGIN
EXTERNAL KDPRL,KGFRL,C1H,C1L,C2H,C2L,COPRIX,CNSTCM; !EXTERNALS USED IN FOLDING
! A REAL TO 1 WD OF PREC
OWN PEXPRNODE ARG1NODE:ARG2NODE;
MAP PEXPRNODE CNODE;
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
%(****IF ARG1 IS EQUAL TO ARG2 -
SUBSTITUTE TRUE FOR A EQ A, A LE A, A GE A
SUBSTITUTE FALSE FOR A LT A, A GT A, A NE A
*******)%
IF .CNODE[ARG1PTR] EQL .CNODE[ARG2PTR]
THEN
RETURN CMBEQLARGS(.CNODE,FALSE);
%(***CHECK FOR BOTH ARGS NEGATED.
TRANSFORM:
-A LT -B = A GT B
-A LEQ -B = A GEQ B
-A EQ -B = A EQ B
-A GT -B = A LT B
-A GEQ -B = A LEQ B
-A NEQ -B = A NEQ B
***)%
IF .CNODE[A1NEGFLG] AND .CNODE[A2NEGFLG]
THEN
BEGIN
CNODE[A1NEGFLG]_0;
CNODE[A2NEGFLG]_0;
IF NOT EQREL(.CNODE[OPERSP])
THEN
CNODE[OPERSP]_REVREL(.CNODE[OPERSP]);
END;
%(**********
IF THE OPERANDS ARE BOTH CONSTANTS, EVALUATE THE RELATIONAL
AND REPLACE IT IN THE TREE BY EITHER TRUE OR FALSE.
IF ONE OF THE ARGS IS A CONSTANT, LET THAT ARG BE THE 2ND ARG.
*************)%
IF .ARG1NODE[OPR1] EQL CONSTFL
AND .ARG1NODE[VALTYPE] NEQ DOUBLOCT !(DONT FOLD OPS ON DOUBLE OCTALS
! SINCE HAVE COMPLICATIONS DUE TO USING KI10
! FORMAT NUMBS AT COMPILE TIME)
THEN
BEGIN
%(****FEB 23,1972 - THE FOLLOWING BLOCK WAS INSERTED TO
PREVENT A BLISS BUG THAT DELETED CODE . THIS BLOCK FORCES
BLISS TO USE 2 TEMP REGS***)%
BEGIN
OWN T,T1,T2,T3;
T_1; T1_2; T2_3; T3_4;
END;
IF .ARG2NODE[OPR1] EQL CONSTFL
AND .ARG2NODE[VALTYPE] NEQ DOUBLOCT
THEN
BEGIN
OWN KN;
OWN K1H,K1L,K2H,K2L; !HI AND LO WDS OF EACH CONST (AFTER ROUND)
%(***FOR REAL VARS AND DP VARS ON KA10, MUST ROUND BEFORE COMPARE***)%
%[761]% IF .ARG1NODE[VALTYPE] EQL REAL
THEN
BEGIN
C1H_.ARG1NODE[CONST1]; !SET UP GLOBALS FOR CONST
C1L_.ARG1NODE[CONST2]; ! FOLDING ROUTINE
%[761]% IF .GFLOAT ! TO ROUND DP TO REAL
%[761]% THEN COPRIX_KGFRL
%[761]% ELSE COPRIX_KDPRL;
CNSTCM(); !DO THE ROUNDING, LEAVE RESULT IN C2H,C2L
K1H_.C2H;
K1L_.C2L
END
ELSE (K1H_.ARG1NODE[CONST1]; K1L_.ARG1NODE[CONST2]); !IF NEEDNT ROUND
%[761]% IF .ARG2NODE[VALTYPE] EQL REAL
THEN
BEGIN
C1H_.ARG2NODE[CONST1]; !SET UP GLOBALS FOR CONST
C1L_.ARG2NODE[CONST2]; ! FOLDING ROUTINE
%[761]% IF .GFLOAT
%[761]% THEN COPRIX_KGFRL
%[761]% ELSE COPRIX_KDPRL;
CNSTCM(); !DO THE ROUNDING, LEAVE RESULT IN C2H,C2L
K2H_.C2H;
K2L_.C2L
END
ELSE (K2H_.ARG2NODE[CONST1]; K2L_.ARG2NODE[CONST2]); !IF NEEDNT ROUND
KN_
BEGIN
IF .ARG1NODE[DBLFLG]
THEN
%(***IF MUST COMPARE 2-WD VAL****)%
BEGIN
CASE .CNODE[OPERSP] OF SET
%(***UNUSED OPERSP CODE - SHOULD NEVER GET HERE***)%
BEGIN
SKERR();
FALSE
END;
%(** LT **)%
(.K1H LSS .K2H)
OR (.K1H EQL .K2H AND .K1L LSS .K2L);
%(** EQ **)%
(.K1H EQL .K2H) AND (.K1L EQL .K2L);
%(** LE **)%
(.K1H LSS .K2H)
OR (.K1H EQL .K2H AND .K1L LEQ .K2L);
%(**UNUSED CODE SHOULD NEVER GET HERE**)%
BEGIN
SKERR();
FALSE
END;
%(** GE **)%
(.K1H GTR .K2H)
OR (.K1H EQL .K2H AND .K1L GEQ .K2L);
%(** NE**)%
(.K1H NEQ .K2H) OR (.K1L NEQ .K2L);
%(** GT **)%
(.K1H GTR .K2H)
OR (.K1H EQL .K2H AND .K1L GTR .K2L);
TES
END
ELSE
%(***IF MUST COMPARE SINGLE-WD VALS***)%
BEGIN
OWN C1,C2;
%(***SET C1 AND C2 TO THE VALS TO BE COMPARED***)%
![1031] Use low or high word of each constant based on VALTP1
![1031] since octals are not converted to reals under GFLOATING
%[1031]% IF .ARG1NODE[VALTP1] EQL INTEG1
%[1031]% THEN C1_.K1L
%[1031]% ELSE C1_.K1H;
%[1031]% IF .ARG2NODE[VALTP1] EQL INTEG1
%[1031]% THEN C2_.K2L
%[1031]% ELSE C2_.K2H;
CASE .CNODE[OPERSP] OF SET
%(***UNUSED OPERSP CODE - SHOULD BEVER GET HERE***)%
BEGIN
SKERR();
FALSE
END;
%(***LT****)%
.C1 LSS .C2;
%(***EQ****)%
.C1 EQL .C2;
%(***LE****)%
.C1 LEQ .C2;
%(***UNUSED OPERSP CODE - SHOULD NEVER GET HERE***)%
BEGIN
SKERR();
FALSE
END;
%(***GE***)%
.C1 GEQ .C2;
%(***NE***)%
.C1 NEQ .C2;
%(***GT***)%
.C1 GTR .C2
TES
END
END;
%(***SET THE VALFLG IN THE PARENT OF CNODE***)%
SETPVAL(.CNODE);
%(***RETURN THE CONSTANT TABLE ENTRY FOR THE VAL OF THIS RELATIONAL***)%
RETURN MAKECNST(LOGICAL,0,
BEGIN
IF .KN THEN TRUE ELSE FALSE
END);
END
%(***IF ARG1 IS A CONSTANT AND ARG2 IS NOT; SWAP THE 2
ARGS ***)%
ELSE
BEGIN
IF NOT EQREL(.CNODE[OPERSP])
THEN
CNODE[OPERSP]_REVREL(.CNODE[OPERSP]);
SWAPARGS(CNODE);
![671] WHEN WE SWAP THE ARGUMENTS, BE SURE TO SWAP THE DEF PTS TOO
%[671]% IF .FLGREG<OPTIMIZE> THEN
%[671]% BEGIN
%[671]% ARG1NODE_.CNODE[DEFPT2];
%[671]% CNODE[DEFPT2]_.CNODE[DEFPT1];
%[671]% CNODE[DEFPT1]_.ARG1NODE
%[671]% END;
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
END;
END;
%(*****IF ONE OF THE ARGS IS ZERO AND THE OTHER IS A SUM, TRANSFORM:
(A+B).REL.0=A.REL.-B
*********)%
IF ( NOT .CNODE[A1VALFLG]) AND (.ARG2NODE[OPR1] EQL CONSTFL)
THEN
BEGIN
IF (.ARG2NODE[CONST1] EQL 0) AND (.ARG2NODE[CONST2] EQL 0) AND (.ARG1NODE[OPR1] EQL ADDOPF)
AND NOT .CNODE[A1NOTFLG]
THEN
BEGIN
%(****MAKE ARG1 UNDER CNODE BE ARG1 UNDER THE SUM, MAKE ARG2 BE
ARG2 UNDER THE SUM WITH THE SIGN REVERSED****)%
CNODE[ARG1PTR]_.ARG1NODE[ARG1PTR];
CNODE[A1FLGS]_.ARG1NODE[A1FLGS];
CNODE[ARG2PTR]_.ARG1NODE[ARG2PTR];
CNODE[A2FLGS]_.ARG1NODE[A2FLGS];
CNODE[A2NEGFLG]_NOT .CNODE[A2NEGFLG];
%(***CORRECT PARENT PTRS IN THE 2 SUBNODES WHICH WERE MOVED***)%
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
IF .ARG1NODE[OPRCLS] EQL DATAOPR
THEN
CNODE[A1VALFLG]_1
ELSE
ARG1NODE[PARENT]_.CNODE;
IF .ARG2NODE[OPRCLS] EQL DATAOPR
THEN
CNODE[A2VALFLG]_1
ELSE
ARG2NODE[PARENT]_.CNODE;
END;
END;
RETURN .CNODE;
END;
GLOBAL ROUTINE P2SKFN(CNODE)=
%(***
INITIAL PASS OF PHASE 2 SKELETON FOR A FUNCTION CALL. CANNOT FORCE
NEG OR NOT DOWN ACROSS A FN CALL.
***)%
BEGIN
EXTERNAL DOWDP,CDONODE; !GLOBAL USED IN DETERMINING WHETHER A
! DO LOOP INDEX CAN LIVE IN A REGISTER
MAP OBJECTCODE DOWDP;
MAP PEXPRNODE CDONODE;
EXTERNAL USERFNFLG; !FLAG INDICATING THAT THIS STMNT HAD A
! CALL TO A USER FUNCTION
MAP OBJECTCODE USERFNFLG;
MAP PEXPRNODE CNODE;
LOCAL ARGUMENTLIST ARGLST;
LOCAL PEXPRNODE FNNAMENTRY;
LOCAL PRVNEGFLG, PRVNOTFLG;
LOCAL PEXPRNODE ARGNODE;
DEBGNODETST(CNODE); !FOR DEBUGGING ONLY
FNNAMENTRY_.CNODE[ARG1PTR];
ARGLST_.CNODE[ARG2PTR];
%(***IF THIS FN IS NOT A LIBRARY FN, SET A GLOBAL INDICATING THAT THIS
STMNT INCLUDES A CALL TO A USER FN***)%
IF .CNODE[OPERSP] NEQ LIBARY THEN USERFNFLG_TRUE;
%(***IF THIS FN IS A STMNT FN AND THIS REFERENCE IS INSIDE A DO LOOP
THEN THE INDEX OF THAT LOOP MUST BE MATERIALIZED (SINCE THE
STMNT FN CAN REFERENCE THE VAR)***)%
IF .FNNAMENTRY[IDATTRIBUT(SFN)] THEN DOWDP[DOMTRLZIX]_1;
%(***PERFORM PHASE 2 SKEL OPTIMS ON ALL ARGS***)%
IF .CNODE[ARG2PTR] NEQ 0
THEN
BEGIN
PRVNEGFLG_.NEGFLG;
PRVNOTFLG_.NOTFLG;
%(*** PROCESS ALL ARGUMENTS ***)%
INCR CT FROM 1 TO .ARGLST[ARGCOUNT]
DO
BEGIN
ARGNODE_.ARGLST[.CT,ARGNPTR];
IF NOT .ARGLST[.CT,AVALFLG]
THEN
%(***UNLESS THIS ARG IS A LEAF OR A COMMON SUBEXPR, PROCESS IT***)%
BEGIN
NEGFLG_FALSE;
NOTFLG_FALSE;
ARGLST[.CT,ARGNPTR]_(.P2SKL1DISP[.ARGNODE[OPRCLS]])(.ARGNODE);
END;
%(***CHECK WHETHER THIS ARG IS THE INDEX OF A DO LOOP THAT
INCLUDES THIS STMNT. IF SO, WILL NOT BE ABLE TO
HAVE THAT LOOP INDEX LIVE IN A REGISTER***)%
IF .ARGLST[.CT,ARGNPTR] EQL .DOWDP[DOINDUC]
THEN DOWDP[DOMTRLZIX]_1;
END;
%(***RESTORE NEGFLG AND NOTFLG TO THE VALS THAT THEY HAD WHEN ENTERED***)%
NEGFLG_.PRVNEGFLG;
NOTFLG_.PRVNOTFLG;
END;
%(***CHECK FOR WHETHER THIS FN SHOULD BE EXPANDED IN LINE. IF SO,TRANSFORM
THIS FNCALL NODE INTO AN "IN-LINE-FN" NODE OR A TYPE-CONVERSION NODE***)%
IF .FNNAMENTRY[IDINLINFLG]
THEN
BEGIN
%(***IN RELEASE 1, WE DONT EXPAND ANYTHING WITH MORE THAN 2 ARGS INLINE***)%
IF .ARGLST[ARGCOUNT] LEQ 2
THEN
BEGIN
CNODE[OPERATOR]_.FNNAMENTRY[IDINLINOPR];
%(***FOR A TYPE-CONVERSION NODE, THE SINGLE ARG IS ARG2***)%
IF .CNODE[OPRCLS] EQL TYPECNV
THEN
BEGIN
CNODE[ARG2PTR]_.ARGLST[1,ARGNPTR];
IF .ARGLST[1,AVALFLG] THEN CNODE[A2VALFLG]_1;
END
ELSE
BEGIN
CNODE[ARG1PTR]_.ARGLST[1,ARGNPTR];
IF .ARGLST[1,AVALFLG]
THEN CNODE[A1VALFLG]_1;
IF .ARGLST[ARGCOUNT] EQL 2
THEN
BEGIN
CNODE[ARG2PTR]_.ARGLST[2,ARGNPTR];
IF .ARGLST[2,AVALFLG]
THEN CNODE[A2VALFLG]_1;
END
ELSE CNODE[ARG2PTR]_0;
END;
%(***RETURN THE CORE THAT WAS USED FOR THE ARGLST TO FREE STORAGE***)%
SAVSPACE(.ARGLST[ARGCOUNT],.ARGLST); !ARGCOUNT IS # OF WDS-1
%(***IF ARG1 UNDER THIS NODE HAS A NEG NODE AS ITS TOP NODE,
FOLD IT OUT***)%
ARGNODE_.CNODE[ARG1PTR];
IF .ARGNODE[OPR1] EQL NEGFL
THEN
BEGIN
CNODE[A1NEGFLG]_1;
CNODE[ARG1PTR]_.ARGNODE[ARG2PTR];
IF .ARGNODE[A2VALFLG]
THEN CNODE[A1VALFLG]_1
ELSE
BEGIN
OWN PEXPRNODE ARG1NODE;
ARG1NODE_.CNODE[ARG1PTR];
ARG1NODE[PARENT]_.CNODE;
END;
%(***RETURN THE SPACE FOR THE NEG TO FREE STORAGE***)%
SAVSPACE(3,.ARGNODE);
END;
END;
END;
RETURN .CNODE;
END;
GLOBAL ROUTINE P2SKARITH(CNODE)=
%(***
INITIAL PASS OF PHASE 2 SKELETON FOR AN ARITHMETIC NODE
***)%
BEGIN
EXTERNAL DOWDP; !GLOBAL USED IN DETERMINING WHETHER A DO-LOOP
! INDEX SHOULD LIVE IN A REG
MAP OBJECTCODE DOWDP;
LOCAL PEXPRNODE ARG1NODE;
LOCAL PEXPRNODE ARG2NODE;
LOCAL V;
MAP PEXPRNODE CNODE;
! MAKE 4 BOOLEAN LOCALS LIVE INSIDE V
!SO THAT RECURSIVE CALLS ARE LESS LIKELY TO
!OVERFLOW OUR STACK! THE BOOLEANS ARE DEFINED BELOW
MACRO PARNEG=35,1$,
PARNOT=34,1$,
ARG1NEG=33,1$,
ARG2NEG=32,1$;
DEBGNODETST(CNODE); !FOR DEBUGGING ONLY
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
%(***FORCE DOWN A NEGATIVE BY:
-(A+B)=-A-B
-(A-B)=-A+B
-(A*B)=(-A)*B
-(A/B)=(-A)/B
***)%
IF .NEGFLG
THEN
BEGIN
CASE .CNODE[OPERSP] OF SET
%(*** FOR ADD ***)%
BEGIN
V<ARG1NEG>_TRUE;
V<ARG2NEG>_TRUE;
V<PARNEG>_FALSE;
END;
%(*** FOR SUB ***)%
BEGIN
CNODE[OPERSP]_ADDOP;
V<ARG1NEG>_TRUE;
V<ARG2NEG>_FALSE;
V<PARNEG>_FALSE;
END;
%(*** FOR MUL ***)%
BEGIN
V<ARG1NEG>_TRUE;
V<ARG2NEG>_FALSE;
V<PARNEG>_FALSE;
END;
%(*** FOR DIV ***)%
BEGIN
V<ARG1NEG>_TRUE;
V<ARG2NEG>_FALSE;
V<PARNEG>_FALSE;
END;
%(*** FOR EXPONENTIATION ***)%
%(*** CANNOT FORCE NEG DOWN ***)%
BEGIN
V<ARG1NEG>_FALSE;
V<ARG2NEG>_FALSE;
V<PARNEG>_TRUE;
END
TES
END
ELSE
BEGIN
V<ARG1NEG>_FALSE;
V<PARNEG>_FALSE;
IF .CNODE[OPERSP] EQL SUBOP
THEN
BEGIN
CNODE[OPERSP]_ADDOP;
V<ARG2NEG>_TRUE;
END
ELSE
V<ARG2NEG>_FALSE;
END;
%(*** CANNOT FORCE DOWN A NOT ***)%
V<PARNOT>_.NOTFLG;
%(********* PROCESS FIRST ARG **********)%
%(****DO NOT WALK DOWN TO A NODE WHICH IS A LEAF OR COMMON SUBEXPR***)%
IF .CNODE[A1VALFLG]
THEN
BEGIN
IF .V<ARG1NEG>
THEN CNODE[A1NEGFLG]_1;
END
ELSE
%(***IF ARG IS NOT A LEAF OR COMMON SUBEXPR***)%
BEGIN
NOTFLG_FALSE;
NEGFLG_ IF .V<ARG1NEG> THEN TRUE ELSE FALSE;
ARG1NODE_(.P2SKL1DISP[.ARG1NODE[OPRCLS]])(.ARG1NODE);
CNODE[A1NEGFLG]_.NEGFLG<0,1>;
CNODE[A1NOTFLG]_.NOTFLG<0,1>;
END;
%(***IF ARG IS A CONSTANT (OR WAS COLLAPSED INTO ONE), PERFORM NEG
ON IT AT COMPILE TIME*****)%
IF .ARG1NODE[OPR1] EQL CONSTFL
THEN
BEGIN
IF .CNODE[A1NEGFLG]
THEN
BEGIN
ARG1NODE_NEGCNST(ARG1NODE);
CNODE[A1NEGFLG]_0;
END;
END;
CNODE[ARG1PTR]_.ARG1NODE;
%(********* PROCESS SECOND ARG ********)%
IF .CNODE[A2VALFLG]
THEN
BEGIN
IF .V<ARG2NEG>
THEN
CNODE[A2NEGFLG]_1;
END
ELSE
BEGIN
NEGFLG_ IF .V<ARG2NEG> THEN TRUE ELSE FALSE;
NOTFLG_FALSE;
ARG2NODE_(.P2SKL1DISP[.ARG2NODE[OPRCLS]])(.ARG2NODE);
CNODE[A2NEGFLG]_.NEGFLG<0,1>;
CNODE[A2NOTFLG]_.NOTFLG<0,1>;
END;
%(***IF ARG IS A CONSTANT (OR WAS COLLAPSED INTO ONE), PERFORM NEG
ON IT AT COMPILE TIME*****)%
IF .ARG2NODE[OPR1] EQL CONSTFL
THEN
BEGIN
IF .CNODE[A2NEGFLG]
THEN
BEGIN
ARG2NODE_NEGCNST(ARG2NODE);
CNODE[A2NEGFLG]_0;
END;
END;
CNODE[ARG2PTR]_.ARG2NODE;
%(*** CHECK FOR
(-A)*(-B)=A*B
(-A)/(-B)=A/B
***)%
IF .CNODE[A1NEGFLG] AND .CNODE[A2NEGFLG]
THEN
BEGIN
IF .CNODE[OPERSP] EQL MULOP
OR .CNODE[OPERSP] EQL DIVOP
THEN
BEGIN
CNODE[A1NEGFLG]_0;
CNODE[A2NEGFLG]_0;
END;
END;
NEGFLG_ IF .V<PARNEG> THEN TRUE ELSE FALSE;
NOTFLG_ IF .V<PARNOT> THEN TRUE ELSE FALSE;
%(****CHECK FOR CONSTANT OPERATIONS AND OPERATIONS ON IDEXTICAL ARGS THAT CAN BE FOLDED***)%
V_ ARSKOPT(.CNODE);
%(***IF EITHER ARG OF AN EXPONENTIATION IS THE INDEX OF A DO LOOP THAT
INCLUDES THAT EXPONENTIATION, CANNOT HAVE THAT LOOP INDEX LIVE IN A REG***)%
IF .CNODE[OPR1] EQL EXPONOPF
THEN
BEGIN
IF .CNODE[ARG1PTR] EQL .DOWDP[DOINDUC] OR
(.CNODE[ARG2PTR] EQL .DOWDP[DOINDUC])
THEN
DOWDP[DOISUBS]_0
END;
RETURN .V;
END;
GLOBAL ROUTINE ARSKOPT(CNODE)=
%(***************************************************************************
FOR AN ARITHMETIC NODE, CHECK FOR OPERATIONS ON CONSTANTS AND ON IDENTICAL ARGS THAT CAN BE FOLDED.
CALLED WITH THE ARG CNODE POINTING TO AN ARITHMETIC EXPRESSION NODE.
***************************************************************************)%
BEGIN
MAP PEXPRNODE CNODE;
OWN PEXPRNODE ARG1NODE:ARG2NODE;
LABEL FOLDCNST;
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
%(***
CHECK FOR BOTH OPERANDS CONSTANTS. IF SO, PERFORM THE
OPERATION AT COMPILE TIME - CREATE A CONSTANT TABLE ENTRY
FOR THE NEW CONSTANT WHICH IS THE RESULTS
***)%
IF .ARG1NODE[OPR1] EQL CONSTFL AND .ARG2NODE[OPR1] EQL CONSTFL
%(***DO NOT FOLD OPERATIONS INVOLVING DOUBLE OCTALS SINCE HAVE COMPLICATIONS
DUE TO KEEPING ALL DOUBLE-PRECISION IN KI10 FORMAT UNTIL THE END***)%
AND .ARG1NODE[VALTYPE] NEQ DOUBLOCT AND .ARG2NODE[VALTYPE] NEQ DOUBLOCT
THEN
FOLDCNST: BEGIN
%(***DO NOT FOLD COMPLEX MULTIPLY AND DIVIDE,*****)%
IF .CNODE[VALTYPE] EQL COMPLEX AND MULORDIV(CNODE)
THEN
LEAVE FOLDCNST;
%(***GLOBALS USED BY THE ASSEMBLY LANGUAGE ROUTINE THAT
PERFORMS THE OPERATIONS ARE
COPRIX, C1H, C1L, C2H, C2L***)%
%(***FOLD CONSTANTS RAISED TO INTEGER POWERS ONLY IF THEY USE 8 OR LESS MULTIPLIES***)%
IF .CNODE[OPERSP] EQL EXPONOP
THEN
BEGIN
%(***DO NOT FOLD DOUBLE-PREC EXPONENTIATION AT COMPILE TIME***)%
IF .CNODE[DBLFLG]
THEN LEAVE FOLDCNST
ELSE
BEGIN
EXTERNAL CNTMPY;
IF .ARG2NODE[VALTP1] EQL INTEG1
AND CNTMPY(.ARG2NODE[CONST2]) LEQ 8 !LESS THAN 8 MULTIPLIES
THEN
COPRIX_KEXPIX(.CNODE[VALTP1])
ELSE LEAVE FOLDCNST
END
END
ELSE
COPRIX_KARITHOPIX(CNODE);
%(***PICK UP ARG1 AND ARG2. WHEN HAVE PROPAGATED CONSTANTS, WILL HAVE TO
WORRY ABOUT NEGFLGS***)%
C1H_.ARG1NODE[CONST1];
C1L_.ARG1NODE[CONST2];
C2H_.ARG2NODE[CONST1];
C2L_.ARG2NODE[CONST2];
%(***COMBINE THE CONSTANTS LEAVING THE RESULTS IN C2H AND C2L***)%
CNSTCM();
%(***SET THE VALFLG IN THE PARENT OF CNODE****)%
SETPVAL(.CNODE);
CNODE_MAKECNST(.CNODE[VALTYPE], .C2H, .C2L);
END;
IF .CNODE[OPRCLS] NEQ DATAOPR !IF DID NOT SUCCEED IN FOLDING THIS NODE ALREADY
THEN
BEGIN
%(****
CHECK FOR ONE OF THE ARGUMENTS A CONSTANT
IF SO, GO ATTEMPT TO MAKE THE
VARIOUS OPTOMIZATIONS THAT CAN BE MADE ON OPS BETWEEN
A VARIABLE(OR EXPRESSION) AND A CONSTANT.
THESE INCLUDE RECOGNIZING CONSTANTS AS BEING
1. ZERO
2. ONE
3. MINUS ONE
4. POWERS OF 2
5. POWER OF 2 PLUS ONE
*******)%
IF .ARG1NODE[OPR1] EQL CONSTFL
THEN
CNODE_ARCMB(.CNODE,.ARG1NODE,.ARG2NODE,TRUE)
ELSE
IF .ARG2NODE[OPR1] EQL CONSTFL
THEN
CNODE_ARCMB(.CNODE,.ARG2NODE,.ARG1NODE,FALSE)
%(********
CHECK FOR:
A+A=2*A
A-A=0
A/A=1
A/-A=-1
***********)%
ELSE
IF (.CNODE[ARG1PTR] EQL .CNODE[ARG2PTR])
THEN
CNODE_CMBEQLARGS(.CNODE,FALSE);
END;
%(****CANONICALIZE CNODE AND RETURN THE RESULT*****)%
RETURN CANONICALIZE(.CNODE);
END;
GLOBAL ROUTINE P2SKLTP(CNODE)=
%(********
INITIAL PASS OF PHASE 2 SKELETON FOR A TYPE-CONVERSION
NODE.
********)%
BEGIN
LOCAL PEXPRNODE ARGNODE;
LOCAL SAVENOTFLG;
MAP PEXPRNODE CNODE;
DEBGNODETST(CNODE); !FOR DEBUGGING ONLY
ARGNODE_.CNODE[ARG2PTR];
IF NOT .CNODE[A2VALFLG]
THEN
%(**PROCESS THE ARGUMENT UNDER THIS NODE.
SIMPLY PASS NEG ON DOWN.
**)%
BEGIN
IF NOT NOCNV(CNODE) !IF THIS IS A TYPE-CNV THAT DOES GENERATE CODE
THEN
BEGIN
SAVENOTFLG_.NOTFLG; !CANNOT PASS A "NOT" DOWN OVER A TYPE CNV
NOTFLG_FALSE;
END;
ARGNODE_(.P2SKL1DISP[.ARGNODE[OPRCLS]])(.ARGNODE); !PROCESS ARG UNDER TPCNV
%(***EXCEPT FOR DUMMY TYPE CONVERSION NODES, CANNOT PASS "NOT"
UP THROUGH THE TYPE CONVERSION***)%
IF NOT NOCNV(CNODE)
THEN
BEGIN
CNODE[A2NOTFLG]_.NOTFLG<0,1>;
NOTFLG_.SAVENOTFLG;
END;
%(***IF HAVE A NEG PASSED UP TO THIS NODE, MUST CHECK WHETHER IT CAN
BE PASSED UP TO THE PARENT OF THIS NODE***)%
IF .NEGFLG AND NOT TAKNEGARG(.CNODE[PARENT])
THEN
%(***IF CANNOT PASS THE NEG BACK UP, PUT IT INTO THE TPCNV NODE***)%
BEGIN
CNODE[A2NEGFLG]_1;
NEGFLG_FALSE;
END;
END;
%(***PERFORM TYPE-CONVERSION ON A CONSTANT****)%
IF .ARGNODE[OPR1] EQL CONSTFL
THEN
BEGIN
C1H_.ARGNODE[CONST1];
C1L_.ARGNODE[CONST2];
IF .CNODE[A2NOTFLG] !IF MUST TAKE THE "NOT" OF THE ARG
THEN
BEGIN
C1H_NOT .C1H;
C1L_NOT .C1L;
END;
IF .CNODE[A2NEGFLG] !IF MUST TAKE THE NEG OF THE ARG
THEN
BEGIN
IF .ARGNODE[VALTYPE] EQL DOUBLPREC OR .ARGNODE[VALTYPE] EQL REAL
THEN
%(***FOR DOUBLE PREC (AND REAL) MUST USE ASSEMBLY LANG ROUTINE
TO TAKE NEG***)%
BEGIN
%[761]% COPRIX_KDNEGB;
CNSTCM();
C1H_.C2H;
C1L_.C2L;
END
ELSE
BEGIN
C1H_-.C1H;
C1L_-.C1L;
END
END;
COPRIX_KTPCNVIX(CNODE);
CNSTCM();
%(***SET THE VALFLG IN THE PARENT OF CNODE***)%
SETPVAL(.CNODE);
RETURN MAKECNST(.CNODE[VALTYPE],.C2H,.C2L);
END;
CNODE[ARG2PTR]_.ARGNODE;
RETURN .CNODE;
END;
GLOBAL ROUTINE P2SKLARR(CNODE)=
%(********
INITIAL PASS OF PHASE 2 SKELETON FOR AN ARRAY REFERENCE.
THE EXPRESSION NODE FOR THE ARRAYREF IS ASSUMED TO HAVE THE
FOLLOWING 2 ARGS:
ARG1PTR - PTR TO THE SYMBOL TABLE ENTRY FOR THE ARRAY NAME
ARG2PTR - PTR TO AN EXPRESSION NODE FOR THE ADDRESS CALCULATION
********)%
BEGIN
MAP PEXPRNODE CNODE;
LOCAL PEXPRNODE SSNODE;
LOCAL PRVNEGFLG,PRVNOTFLG;
DEBGNODETST(CNODE); !FOR DEBUGGING ONLY
%(*****UNLESS THE ADDRESS-CALCULATION IS A LEAF, PERFORM THE
PHASE 2 SKEL OPTIMIZATIONS ON IT****)%
IF NOT .CNODE[A2VALFLG]
THEN
BEGIN
SSNODE_.CNODE[ARG2PTR];
PRVNEGFLG_.NEGFLG;
PRVNOTFLG_.NOTFLG;
NEGFLG_FALSE;
NOTFLG_FALSE;
CNODE[ARG2PTR]_(.P2SKL1DISP[.SSNODE[OPRCLS]])(.SSNODE);
CNODE[A2NEGFLG]_.NEGFLG<0,1>;
CNODE[A2NOTFLG]_.NOTFLG<0,1>;
NEGFLG_.PRVNEGFLG; !CANNOT PASS NEG/NOT DOWN OVER AN
! ARRAYREF NODE; HENCE IF WERE TRYING TO DO SO,
! PASS THEM BACK UP TO PARENT
NOTFLG_.PRVNOTFLG;
END;
RETURN .CNODE;
END;
GLOBAL ROUTINE P2SKNEGNOT(CNODE)=
%(***************************************************************************
INITIAL PASS OF PHASE 2 SKEL FOR A NEG OR NOT NODE
TRANSFORMS:
-(-X)=X
NOT(NOT X)=X
PERFORMS NEG/NOT ON A CONSTANT
PASSES NEG AND NOT ON DOWN TO BOTTOMMOST NODES
IN MANY CASES
WHEN A NEG/NOT CANNOT BE PASSED DOWN ANY FURTHER, THE PARENT
NODE HAS A FLAG SET INDICATING "NEGATE(OR COMPLEMENT) THE
FIRST (OR 2ND) ARG";
THE NEGATE/NOT NODE IS REMOVED FROM THE TREE.
A NEGATE CANNOT BE PASSED DOWN FROM ABOVE OVER A NOT. IF THIS
SITUATION ARISES (EG -(NOT X)), THE NEG WILL BE PASSED BACK UP
WHEN THE NOT IS ENCOUNTERED AND IF THE NOT CANNOT BE PROPAGATED DOWN
THE NOT NODE MUST BE LEFT IN THE TREE.
SIMILARLY, A NOT CANNOT BE PROPAGATED OVER A NEGATE.
WHEN A NEGATE OR NOT CANNOT BE PROPAGATED DOWNWARD, THEN
DEPENDING ON WHAT THE PARENT NODE OVER THE NEG/NOT NODE IS, THE NEG OR
NOT MAY IN SOME CASES BE PROPAGATED BACK UPWARD.
***************************************************************************)%
BEGIN
EXTERNAL SETPIMMED;
MAP PEXPRNODE CNODE;
LOCAL PEXPRNODE ARGNODE;
OWN PEXPRNODE PARNODE; !PTR TO PARENT NODE
%(***DEFINE MACRO TO REMOVE THE NEG/NOT NODE FROM THE TREE***)%
MACRO REMOVE=
BEGIN
%(***IF ARG IS A LEAF, SET VALFLG IN PARENT OF CNODE***)%
IF .ARGNODE[OPRCLS] EQL DATAOPR
OR .ARGNODE[OPRCLS] EQL REGCONTENTS
THEN
BEGIN
SETPVAL(.CNODE);
%(***IF THE IMMEDIATE-FLAG WAS SET IN THE NEG/NOT NODE, SET IT
IN THE PARENT OF THE NEG/NOT NODE***)%
IF .CNODE[A2IMMEDFLG]
THEN SETPIMMED(.CNODE);
END
%(***OTHERWISE SET PARENT PTR OF THE ELEMENT BELOW CNODE
AND IF HAVE A PARENFLG ON CNODE, PUT IT ON THE ELEMENT BELOW**)%
ELSE
BEGIN
ARGNODE[PARENT]_.CNODE[PARENT];
IF .CNODE[PARENFLG] THEN ARGNODE[PARENFLG]_1;
END;
RETURN .ARGNODE;
END$;
%(***DEFINE A MACRO TO LEAVE A NEG NODE IN THE TREE, AND RETURN WITH NEGFLG=FALSE***)%
MACRO LEAVENEG=
BEGIN
NEGFLG_FALSE;
CNODE[OPERSP]_NEGOP; !THIS NODE MAY HAVE ORIGINALLY BEEN A NOT.
! EG .NOT.(.NOT.(-X))
RETURN .CNODE;
END$;
%(***DEFINE A MACRO TO LEAVE A NOT NODE IN THE TREE, AND RETURN WITH NOTFLG=FALSE***)%
MACRO LEAVENOT=
BEGIN
NOTFLG_FALSE;
CNODE[OPERSP]_NOTOP; !THIS NODE MAY HAVE ORIGINALLY BEE A NEG.
! EG -(-(.NOT.X))
RETURN .CNODE;
END$;
DEBGNODETST(CNODE); !FOR DEBUGGING ONLY
ARGNODE_.CNODE[ARG2PTR];
IF .CNODE[OPERSP] EQL NEGOP
THEN
%(***IF CNODE IS A 'NEG' NODE (UNARY MINUS)***)%
BEGIN
%(***IF WERE TRYING TO PROPAGATE A 'NOT' FROM ABOVE
CANNOT PROPAGATE IT ACROSS A NEG NODE***)%
IF .NOTFLG
THEN
RETURN NOTOFNEG(.CNODE);
NEGFLG_NOT .NEGFLG;
END
ELSE
IF .CNODE[OPERSP] EQL NOTOP
THEN
%(***IF CNODE IS A 'NOT' NODE***)%
BEGIN
IF .NEGFLG
THEN
%(***IF WERE TRYING TO PROPAGATE A 'NEG' FROM ABOVE,
CANNOT PROPAGATE IT ACROSS A 'NOT' NODE***)%
RETURN NEGOFNOT(.CNODE);
NOTFLG_NOT .NOTFLG;
END;
IF .CNODE[A2VALFLG]
THEN
%(***IF THE ARGUMENT UNDER CNODE IS A LEAF***)%
BEGIN
%(****IF THE ARG IS A CONSTANT, CREATE A NEW CONSTANT TABLE ENTRY***)%
IF .ARGNODE[OPR1] EQL CONSTFL
THEN
BEGIN
IF .NEGFLG
THEN
%(****FOR NEG***)%
BEGIN
NEGFLG_FALSE;
%(***SET THE VALFLG IN THE PARENT OF THE NEG***)%
SETPVAL(.CNODE);
RETURN NEGCNST(ARGNODE);
END;
IF .NOTFLG
THEN
%(****FOR NOT***)%
BEGIN
NOTFLG_FALSE;
%(***SET THE VALFLG IN THE PARENT OF THE NOT***)%
SETPVAL(.CNODE);
RETURN NOTCNST(ARGNODE);
END;
END;
END
ELSE
%(***IF ARG IS NOT A LEAF, TRY TO PROPAGATE NEG AND NOT OVER IT***********)%
BEGIN
ARGNODE_ (.P2SKL1DISP[.ARGNODE[OPRCLS]])(.ARGNODE);
CNODE[ARG2PTR]_.ARGNODE;
END;
%(****IF ARE LEFT WITH A NEG OR NOT THAT COULD NOT BE PROPAGATED DOWN, DECIDE
WHETHER OR NOT TO COLLAPSE IT UP INTO THE PARENT ON THE BASIS
OF THE OPERATOR CLASS OF THE PARENT
*******)%
IF .NEGFLG
THEN
BEGIN
IF TAKNEGARG(.CNODE[PARENT])
THEN
REMOVE
ELSE
LEAVENEG;
END
ELSE
%(***IF HAVE A NOT THAT WERE UNABLE TO PROPAGATE DOWN***)%
IF .NOTFLG
THEN
BEGIN
IF TAKNOTARG(.CNODE[PARENT]) !IF THE NOT CAN BE ABSORBED BY THE PARENT
THEN REMOVE ! REMOVE THE NOT NODE AND PROPAGATE
! THE NOT UP TO THE PARENT
ELSE LEAVENOT; !OTHERWISE LEAVE THE NOT NODE
END
%(***IF THE NEG OR NOT WAS ABSORBED BELOW THIS NODE, CAN REMOVE THE NEG/NOT NODE
FROM THE TREE****)%
ELSE
REMOVE;
END;
END
ELUDOM