Trailing-Edge
-
PDP-10 Archives
-
BB-4157F-BM_1983
-
fortran/compiler/cmplex.bli
There are 26 other files named cmplex.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) DIGITAL EQUIPMENT CORPORATION 1972, 1983
!AUTHOR: S. MURPHY/HPW/MD/JNG/SJW/DCE/TFV/AHM/CDM
MODULE CMPLEX(SREG=#17,VREG=#15,FREG=#16,DREGS=4,RESERVE(0,1,2,3))=
BEGIN
GLOBAL BIND CMPLEV = 7^24 + 0^18 + #1567; ! Version Date: 24-Jun-82
%(
***** Begin Revision History *****
115 ----- ----- ADD ROUTINES CMPE1LIST AND CMPE2LIST TO
COMPUTE COMPLEXITY FOR E1LISTCALL AND
E2LISTCALL NODES
116 ----- ----- ALLOCATE CONSTANT ZERO IN E1INCR OR E2INCR
FIELD OF E1LISTCALL OR E2LISTCALL NODES
117 ----- ----- KEEP VALUE OF "PAIRMODE" CORRECTLY INSIDE OF
IOLISTS ("CMPLIOLST" NEEDED MODIFYING)
KEEP VALUE OF "FNREF" INSIDE OF IOLISTS
SET "FNREF" WHEN A FNCALL IS ENCOUNTERED
118 ----- ----- IN A SYMMETRIC BINARY OPERATION WITH TWO
REGISTER ARGUMENTS ONE OF WHICH IS THE
FUNCTION RETURN REGISTER, PERFORM CALCULATIONS
IN THE OTHER REGISTER
119 ----- ----- IMPROVE COMPLEXITY CALCULATION FOR DATACALL,
E1LISTCALL, AND E2LISTCALL NODES
120 ----- ----- SAME FOR FUNCTION AND SUBROUTINE CALLS
121 ----- ----- ADD CMPLEXITY FOR CMPLX IN LINE
122 ----- ----- ALLOW "EXCHARGS" TO BE CALLED FOR IN LINE FNS
123 ----- ----- REMOVE ALL REFERENCES TO SQROP,CUBOP,P4OP
(THEY ARE ALL NOW UNDER EXPCIOP)
124 ----- ----- CHANGE REFS TO THE MACRO "POWEROF2" TO "POWOF2"
125 ----- ----- FIX BUG IN CMPILF; DIM CANNOT HAVE AN IMMED MODE 2ND ARG
126 ----- ----- ?
127 301 16154 SET FNCALLSFLG IN CSTMNT WHEN CHANGING ** TO FUNCTION
CALL, (JNT)
128 344 17768 PROPAGATE FNCALLSFLG TO NEG/NOT NODE EVEN
IF COMPLEXITY OF ARGUMENT IS ZERO., (MD)
129 411 19537 DON'T EXCHANGE ARGS TO MAX OR MIN FUNCTION IF
FIRST ARG IS NEGATIVE., (JNG)
***** Begin Version 5 *****
130 412 ----- IN CMPLA FOR DOUBLE ARRAYREF FOR KA10, PARENT
COMPLEXITY MUST BE AT LEAST 3, (SJW)
131 426 18816 SET FNCALLSFLG FOR STATEMENTS CONTAINING
IMPLICIT FN CALLS SO 0,1, 16 WILL BE SAVED., (JNG)
132 510 ----- DON'T LOOK FOR ALCRETREGFLG IN DATAOPR NODES., (JNG)
***** Begin Version 5A *****
133 622 11020 COMPLEXITY OF COMPLEX ARRAY REF SHOULD BE GTR 2, (DCE)
***** Begin Version 5B *****
134 730 28275 IN LINE FUNCTIONS OF FORM A=MIN(A,EXPR) MAY
DOUBLY ASSIGN A REGISTER., (DCE)
***** Begin Version 6 *****
135 761 TFV 1-Mar-80 -----
Remove KA10FLG and add new /GFLOATING exponential routine
names (GEXP vs DEXP etc.)
139 1127 AHM 22-Sep-81 ------
Change erroneous (and potentially dangerous) use of IDTARGET
to TARGADDR in ARRNARGBLK.
***** Begin Version 7 *****
136 1202 DCE 1-Jul-80 -----
For expressions on output lists, we need to allocate potential
constants in the lists.
137 1211 DCE 29-Apr-81 -----
Do complexity analysis for final loop value assignments (ELISTs).
138 1253 CKS 11-Aug-81
Do complexity for character arrayref nodes. Same as numeric arrayrefs
but don't remove constant term from subscript expression. Also don't
ADDREGCANDIDATE the subscript since it will be destroyed by the ADJBP.
140 1422 TFV 12-Nov-81 ------
Modify CMPLFNCALL for character functions. The first argument on the
argument list is the descriptor for the result. The value is not
returned in AC0, AC1, but they maybe clobbered.
141 1431 CKS 15-Dec-81
Add CMPLXSUBSTR to compute complexity for substring nodes
1474 TFV 15-Mar-82
Add CMPLCONCAT to compute the complexity of concatenation nodes.
Concatenations are function calls. The first argument is the
descriptor for the result. Since it has not yet been set up,
CMPLFNARGS has to be changed to ignore the first argument. This
is done by adding another argument to the call.
1505 AHM 12-Mar-82
Have EXPTOFNCALL set the psect index of symbol table entries
for exponentiation functions to PSCODE in order to relocate
those references by .CODE.
1507 AHM 14-Mar-82
Make CMPLIOLST, CMPIOCALL, CMPE1LIST and CMPE2LIST call
ALOCONST for SLIST/ELIST increments and counts so we can get
rid of immediate I/O list args.
1520 DCE 25-Mar-82
Fix up ELISTS so that constants in I/O lists get allocated,
e. g., (A(I),1234,I=1,10).
1551 AHM 3-Jun-82
Remove edit 1505 from this module because external references
will not have a psect index set in the STE.
1567 CDM 24-JUN-82
Set complexities for inline functions
***** End Revision History *****
)%
SWITCHES NOLIST;
REQUIRE FIRST.BLI;
REQUIRE TABLES.BLI;
SWITCHES LIST;
FORWARD
SETCOMPLEXITY,
ARRNARGBLK(2),
CMPLA,
CMARGS,
EXPTOFNCALL,
PRCNSTARG(3),
CMPVBOOL,
CMPLBL,
CMPLREL,
%1474% CMPLCONCAT, ! Compute the complexity of a CONCATENATION node
CMPLFNCALL,
CMPFNARGS(3),
CMPTPCNV,
CMPLXARRAY,
CMPILF,
CMPLXSUBSTR,
CMPLIOLST,
CMPIOCALL(1),
CMPE1LIST(1),
CMPE2LIST(1),
SNGARGPROP(2),
EXCHARGS(1);
EXTERNAL
ADDREGCANDATE, ! Routine in basic-block register allocator to
! add a variable to the set of variables whose
! values are left in registers by the
! computation of statements in the block
ALOCONST,
C1H,
C1L,
CSTMNT,
CSTMNT,
CMSTMN,
CGERR,
CLOBBREGS,
CORMAN, ! Routine to get dynamic core
%1211% CMSTMN,
CSTMNT, ! Pointer to source statement node
DNEGCNST,
ENTRY, ! Holds name that TBLSEARCH looks for
FNREF, ! Global flag for this statement includes a
! function call
GBSYREGS,
MAKEPR,
MAKPR1,
NAME, ! Holds name of which hash table to search
ONEPLIT, ! Points to a constant table entry for the number 1
PAIRMODE, ! Global flag that will be set to true if any
! operations are encountered that require
! register pairs
PROPNEG, ! Routine to propagate a negate (UTIL)
RESNAME,
SAVREGCONTAINING, ! Routine to set flag in the previous
! reference to a variable so that the register
! containing it will be saved (CMPBLO)
SAVSPACE,
SRCHREGCANDATE, ! Routine in basic-block allocator that checks
! whether or a given variable is in the set of
! variables whose values were left in registers
! by the computation of preceeding statements
STBSYR,
STCMCSB,
STRGCT,
TBLSEARCH, ! Searches hash tables
TREEPTR;
%(***************************************************************************
LOCAL REGISTER ALLOCATION MODULE.
INCLUDES 2 PASSES OVER AN EXPRESSION TREE.
ON THE "COMPLEXITY WALK" (IE THE ROUTINE SETCOMPLEXITY AND ALL THE
ROUTINES IT CALLS), THE NODES ARE REARRANGED TO REDUCE THE NUMBER
OF REGISTERS NECESSARY TO COMPUTE THEM, AND THE MINIMUM NUMBER OF REGS NECESSARY
IS SAVED IN EACH NODE.
AT THIS TIME CONSTANTS THAT CAN BE USED "IMMED MODE" ARE RECOGNIZED
AND SPACE IS ALLOCATED FOR ALL OTHERS.
THE CONSTANT PART OF AN ARRAY ADDRESS CALC IS ALSO ADDED IN TO
THE INSTRUCTION ADDRESS AT THIS TIME.
THE 2ND WALK (THE ROUTINES "ALCINREG" AND "ALCINTMP") ALLOCATES
REGISTERS(AND/OR TEMPORARIES) FOR EACH BINARY/UNARY OPERATION TO BE
PERFORMED - TARGETING THE VALUE OF AN EXPRESSION TO A PARTICULAR
REG/TMP
THE GLOBAL "TREEPTR" IS USED IN BOTH THESE WALKS TO POINT TO
THE NODE OF THE EXPRESSION TREE BEING PROCESSED.
***************************************************************************)%
MAP BASE CSTMNT;
MAP PEXPRNODE TREEPTR;
GLOBAL ROUTINE SETCOMPLEXITY=
%(***************************************************************************
ROUTINE TO COMPUTE THE COMPLEXITY (IE # OF REGS NECESSARY FOR
COMPUTATION) OF EXPRESSION NODES AND STORE THAT VALUE INTO
THE NODE ITSELF
ALSO TRIES TO MAKE ARG1 BE THE ARGUMENT MOST LIKELY TO BE COMPUTED INTO
A REGISTER.
ALSO SETS THE FLAG FNCALLSFLG WHICH INDICATES THAT REG 0 GETS CLOBBERED UNDER
THIS NODE.
ALSO, WHEN ARG1 OF A GIVEN NODE WILL BE COMPUTED INTO "RETREG" (IE FN RETURN REG)
THEN IF POSSIBLE ASSIGNS THE PARENT TO BE COMPUTED INTO "RETREG"
CALLED WITH THE GLOBAL "TREEPTR" POINTING TO THE NODE TO BE
PROCESSED
RETURNS THE VALUE OF THE COMPLEXITY OF THIS NODE
***************************************************************************)%
BEGIN
REGISTER PEXPRNODE CNODE:ARGNODE; !PTR TO THE NODE BEING PROCESSED
OWN CMPLX1;
CNODE_.TREEPTR;
IF .CNODE[DBLFLG] !IF THIS NODE IS DP OR COMPLEX
THEN PAIRMODE_TRUE; ! THEN REG PAIRS WILL BE NEEDED
RETURN
BEGIN
CASE .CNODE[OPRCLS] OF SET
%(*******FOR BOOLEAN OPERATIONS*******)%
CNODE[COMPLEXITY]_CMPVBOOL();
%(******FOR DATA ITEMS******************)%
%(*******RETURN 0, BUT DO NOT SET ANYTHING IN THE ENTRY***)%
0;
%(******FOR RELATIONALS*********************)%
%(********NEED 1 MORE REG THAN DO FOR CONTROL-TYPE RELATIONALS****)%
%(*******MUST CHECK FOR DOUBLE-PREC ARGS UNDER THIS SINGLE-WD NODE*****)%
CNODE[COMPLEXITY]_CMPLREL()+1;
%(*******FOR FUNCTION CALLS*****************)%
CNODE[COMPLEXITY]_CMPLFNCALL();
%(*******FOR ARITHMETIC EXPRESSIONS**********)%
BEGIN
CMPLX1_CMPLA();
CNODE[COMPLEXITY]_(IF .CNODE[OPERATOR] EQL INTDIVIDE
THEN (
PAIRMODE_TRUE; !A REG PAIR WILL BE NEEDED
IF .CMPLX1 GTR 2 !AT LEAST 2 REGS
THEN .CMPLX1 !WILL BE NEEDED
ELSE 2)
ELSE .CMPLX1)
END;
%(*******FOR TYPE CONVERSION****************)%
CNODE[COMPLEXITY]_CMPTPCNV();
%(******FOR ARRAY REFERENCE***************)%
%(*******MUST GET THE VALUE OF THE OFFSET INTO A REGISTER - THUS
NEED AS MANY REGS AS NEED TO COMPUTE THAT VAL, OR 1 REG
IF NO COMPUTATION IS NECESSARY*******)%
CNODE[COMPLEXITY]_CMPLXARRAY();
%(*******FOR COMMON SUBEXPRESSION NODE*******)%
%(*********RETURN 0 - DO NOT SET FIELD IN NODE*****)%
0;
%(*******FOR NEG/NOT NODES (THERE SHOULD BE VERY FEW OF THESE THAT COULDNT BE
PROPAGATED OUT*******)%
CNODE[COMPLEXITY]_BEGIN
ARGNODE_.CNODE[ARG2PTR];
IF .ARGNODE[OPR1] EQL CONSTFL !IF ARG IS A CONST
THEN ALOCONST(.ARGNODE); !THIS NODE WILL USUALLY HAVE BEEN
! FOLDED INTO THE CONSTANT, IF NOT
! ALLOCATE CORE FOR THE CONST
TREEPTR_.CNODE[ARG2PTR];
CMPLX1_SETCOMPLEXITY();
IF .CMPLX1 EQL 0
THEN
BEGIN
%(***IF ARG IS EQL TO VAR ON LHS OF ASMNT***)%
IF .ARGNODE EQL .RESNAME
THEN CNODE[RESRFFLG]_1;
%(***IF ARG IS A FUNCTION CALL ***)%
IF .ARGNODE[OPRCLS] NEQ DATAOPR
AND .ARGNODE[OPRCLS] NEQ CMNSUB
THEN SNGARGPROP(.CNODE,.ARGNODE);
%(***IF ARG COULD HAVE BEEN LEFT IN A
REG BY A EARLIER STMNT, DO SO***)%
SAVREGCONTAINING(.ARGNODE);
%(***VAL OF CMPLX IS 1***)%
1
END
ELSE
BEGIN
%(***IF ARG IS COMPUTED INTO FN-RET REG
COMPUTE VAL OF THIS NODE THERE ALSO***)%
SNGARGPROP(.CNODE,.ARGNODE);
.CMPLX1
END
END;
%(*****FOR SPECIAL OPS INTRODUCED BY PHASE 2 SKELETON****)%
%(*******P2MUL,P2DIV, AND EXPCIOP TO A POWER THAT IS A POWER OF TWO TAKE NO EXTRA REGISTERS OVER
THOSE NECESSARY TO GET THE ARG INTO A REG.
P2PL1MUL NEEDS 1 REG IF ARG IS A PROGRAM VARIABLE
OTHERWISE, EITHER 2 REGS OR AS MANY AS ARE
NEEDED TO COMPUTE THE ARG (WHICHEVER IS GREATER)
********)%
CNODE[COMPLEXITY]_
BEGIN
ARGNODE_.CNODE[ARG1PTR];
IF .CNODE[A1VALFLG]
THEN
BEGIN
%(**IF ARG COULD HAVE BEEN LEFT IN A REG BY AN EARLIER STMNT, DO SO**)%
SAVREGCONTAINING(.ARGNODE);
%(***IF ARG IS A CONSTANT, DECIDE WHETHER TO ALLOCATE CORE FOR IT**)%
IF .ARGNODE[OPR1] EQL CONSTFL
THEN PRCNSTARG(.CNODE,.ARGNODE,TRUE)
ELSE
%(***IF ARG IS THE VARIABLE ON THE LHS OF THE ASSIGNMENT
STMNT, SET "RESRFFLG" IN CNODE***)%
IF .ARGNODE EQL .RESNAME THEN CNODE[RESRFFLG]_1;
1
END
ELSE
BEGIN
TREEPTR_.ARGNODE;
CMPLX1_SETCOMPLEXITY();
%(***IF ARG CONTAINED ANY FNCALLS OR ANY REFERENCES TO THE
LHS OF ASMNT, SET FLAGS IN CNODE***)%
IF .ARGNODE[RESRFFLG] THEN CNODE[RESRFFLG]_1;
IF .ARGNODE[FNCALLSFLG] THEN CNODE[FNCALLSFLG]_1;
%(***IF ARG WAS COMPUTED INTO FN-RETURN REG, THEN FOR
P2MUL,P2DIV, AND EXPCIOP TO A POWER OF 2 WANT TO
COMPUTE THE PARENT IN FN-RETURN REG***)%
IF .ARGNODE[ALCRETREGFLG]
THEN
BEGIN
MACRO CMPINRETREG=
BEGIN
CNODE[TARGTAC]_RETREG;
CNODE[INREGFLG]_1;
CNODE[A1SAMEFLG]_1;
CNODE[ALCRETREGFLG]_1;
END$;
CASE .CNODE[OPERSP] OF SET
CMPINRETREG; !P2MUL
CMPINRETREG; !P2DIV
BEGIN END; !P2PL1MUL
CGERR(); !(SQROP HAS BEEN REMOVED)
CGERR(); !CUBOP HAS BEEN REMOVED
CGERR(); !P4OP HAS BEEN REMOVED
BEGIN !EXPCIOP
IF POWOF2(.CNODE[ARG2PTR]) THEN CMPINRETREG;
END;
TES;
END;
%(***IF ARG HAS COMPLEXITY 0, STILL NEED 1 REG***)%
IF .CMPLX1 EQL 0
THEN 1
ELSE
%(***IF ARG HAS COMPLEXITY GEQ 2, THEN NEED SAME NUMBER
OF REGS FOR PARENT AS DO FOR ARG***)%
IF .CMPLX1 GEQ 2
THEN .CMPLX1
ELSE
%(***IF ARG HAS COMPLEXITY 1, THEN FOR P2MUL,P2DIV,
AND EXPCIOP TO A POWER OF 2, NEED ONLY 1 REG.
FOR P2PL1MUL AND EXPCIOP TO A NUMBER OTHER THAN A POWER OF 2
NEED 2 REGS******)%
( CASE .CNODE[OPERSP] OF SET
1; !FOR P2MUL
1; !FOR P2DIV
2; !FOR P2PL1MUL
CGERR(); !FOR SQROP(NO LONGER USED)
CGERR(); !FOR CUBOP(NO LONGER USED)
CGERR(); !FOR P4OP (POWER OF 4)
2; !FOR EXPCIOP
TES )
END
END;
%(****FOR FIELD-REF: NOT IN RELEASE 1**************)%
CGERR();
%(***FOR STORECLS: SHOULD NOT BE ENCOUNTERED BEFORE THE REGISTER-ALLOCATION PASS**)%
CGERR();
%(***FOR REGCONTENTS: COMPLEXITY IS 0*****)%
0;
%(***FOR LABOP: SHOULD NEVER GET HERE*************)%
CGERR();
%(***FOR STATEMENT: SHOULD NEVER GET HERE*****)%
CGERR();
%(***FOR IOLIST ELEMENT: SHOULD NEVER GET HERE*******)%
CGERR();
%(***FOR IN-LINE FUNCTIONS*************************)%
CNODE[COMPLEXITY]_CMPILF();
%1431% %(***FOR SUBSTRING***)%
%1431% CNODE[COMPLEXITY] _ CMPLXSUBSTR();
%1474% ! CONCATENATION
%1474% CNODE[COMPLEXITY] = CMPLCONCAT();
TES
END;
END; ! of SETCOMPLEXITY
GLOBAL ROUTINE ARRNARGBLK(REFPNTR,VLUPNTR)=
%(**********************************************************************
ROUTINE TO DETERMINE IF AN ARRAY REFENCE APPEARING IN
AN ARGBLK IS OF THE FORM A(1) WHERE A IS A FORMAL ARRAY
IF SO, WE WANT TO SUBSTITUTE THE NAME OF THE FORMAL
ARRAY FOR THE ARRAYREFERENCE
CALLED WITH REFPNTR POINTING TO THE REFERENCE
TO THE ARRAY AND VLUPNTR POINTING TO
THE APPRPARIATE VALFLG (REFPNTR AND
VLUPNTR ARE BYTE POINTERS)
**********************************************************************)%
BEGIN
TREEPTR_..REFPNTR; !RESET TREEPTR
IF .TREEPTR[OPRCLS] EQL ARRAYREF THEN
IF .TREEPTR[ARG2PTR] NEQ 0 THEN
IF .TREEPTR[TARGADDR] EQL 0 THEN !1127
BEGIN
LOCAL PEXPRNODE ARROFFSET;
ARROFFSET_.TREEPTR[ARG2PTR];
IF .ARROFFSET[OPR1] EQL FMLVARFL THEN
BEGIN
LOCAL PEXPRNODE ARRNAME;
ARRNAME_.TREEPTR[ARG1PTR];
IF .ARRNAME[OPR1] EQL FMLARRFL THEN
IF .ARRNAME[IDSYMBOL] EQL .ARROFFSET[IDSYMBOL] THEN
BEGIN
SAVSPACE(EXSIZ-1,.TREEPTR);
.REFPNTR_TREEPTR_.ARRNAME; !SUBSTITUE ARRAY NAME
IF .VLUPNTR NEQ 0 THEN .VLUPNTR_1;
RETURN TRUE
END
END
END;
RETURN FALSE
END; ! of ARRNARGBLK
GLOBAL ROUTINE CMPLA=
%(***************************************************************************
ROUTINE TO COMPUTE THE COMPLEXITY OF AN ARITH OR NON-CONTROL
TYPE BOOLEAN
RETURNS THE VAL OF THE COMPLEXITY
ALSO TRIES TO MAKE ARG1 BE THE ARGUMENT MOST LIKELY TO BE COMPUTED INTO
A REGISTER.
ALSO SETS THE FLAGS "FNCALLSFLG", "A1IMMEDFLG", "A2IMMEDFLG".
ALLOCATES CORE FOR CONSTANTS WHICH ARE NOT IMMED-SIZE AND HENCE MUST BE STORED
ALSO, WHEN ARG1 OF A GIVEN NODE WILL BE COMPUTED INTO "RETREG" (IE FN RETURN REG)
THEN IF POSSIBLE ASSIGNS THE PARENT TO BE COMPUTED INTO "RETREG"
CALLED WITH THE GLOBAL "TREEPTR" POINTING TO THE NODE TO BE
PROCESSED
***************************************************************************)%
BEGIN
LOCAL PEXPRNODE CNODE; !PTR TO THE NODE BEING PROCESSED
REGISTER PEXPRNODE ARG1NODE;
REGISTER PEXPRNODE ARG2NODE;
LOCAL CMPLX1,CMPLX2; !COMPLEXITY OF THE ARGS UNDER CNODE
LOCAL RETVAL; ! RETURN VALUE
OWN T1;
OWN AADDR; !BASE ADDRESS FOR THE ARRAY
%(****TO SWAP THE INFO ABOUT THE 2 ARGS WHEN SWAP THE 2 ARGS***)%
MACRO SWPARGDATA =
BEGIN
T1_.CMPLX1;
CMPLX1_.CMPLX2;
CMPLX2_.T1;
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
END$;
%(**CHECK WHETHER THIS EXPR WILL BE EVALUATED BY
CALLING A LIBRARY FN(EG IF IT IS COMPLEX MUL,DIV OR A DP OP ON THE KA10)
SET A GLOBAL FLAG INDICATING WHETHER THIS PROGRAM INCLUDES ANY CALLS TO SUCH FNS**)%
IF USEFNCALL(TREEPTR) THEN TREEPTR[FNCALLSFLG]_LIBARITHFLG_TRUE;
%(****WILL TREAT EXPONENTIATION AS A FUNCTION CALL. THEREFORE TRANSFORM
ANY EXPONENTIATION NODES TO FUNCTION-CALL NODES AND CALL THE ROUTIEN TO PERFORM
COMPLEXITY OF A FN-CALL
********)%
IF .TREEPTR[OPR1] EQL EXPONOPF
THEN
BEGIN
EXPTOFNCALL();
RETURN CMPLFNCALL();
END;
CNODE_.TREEPTR;
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
%(****FIND COMPLEXITIES OF THE 2 ARGS, IF EITHER ARG IS A CONSTANT PROCESS IT
ALSO PROPAGATE THE FLAGS FNCALLSFLG, AND RESRFFLG UP FROM THE ARGS***)%
CMARGS();
%(***GET COMPLEXITY OF 1ST ARG****)%
CMPLX1_(IF .CNODE[A1VALFLG] THEN 0 ELSE .ARG1NODE[COMPLEXITY]);
%(**GET COMPLEXITY OF 2ND ARG*******)%
CMPLX2_(IF .CNODE[A2VALFLG] THEN 0 ELSE .ARG2NODE[COMPLEXITY]);
%(****WILL ALWAYS WANT ARG1 TO BE COMPUTED INTO A REGISTER, THEREFORE IF EITHER ARG
1. MUST BE IN A TEMPORARY
2. IS A SIMPLE DATA ITEM WHICH REQUIRES NO COMPUTATION
3. IS AN ARRAY REFERENCE WHICH MAY BE PICKED UP WITHOUT COMPUTING
IT INTO A REG
4. IS A COMMON SUBEXPRESSION
LET THAT ARG BE ARG2 IF POSSIBLE
********)%
IF NOT .CNODE[A2VALFLG]
AND NOT .CNODE[MEMCMPFLG] !DO NOT REORDER THE ARGS OF AN OPERATION
! THAT WILL BE PERFORMED TO MEMORY
THEN
BEGIN
IF .CNODE[A1VALFLG]
THEN
%(***IF EITHER ARG IS A DATA ITEM OR COMMON SUBEXPR, THAT ARG SHOULD
ALWAYS BE ARG2 IF POSSIBLE**********)%
BEGIN
IF EXCHARGS(.CNODE)
THEN
%(***IF WERE ABLE TO EXCHANGE ARG1 AND ARG2, THEN EXCHANGE
THE DATA ABOUT THEM AS WELL***)%
SWPARGDATA;
END
ELSE
IF .ARG2NODE[OPRCLS] NEQ ARRAYREF
THEN
%(****WHEN NEITHER ARG IS A SIMPLE DATA ITEM, THEN IF EITHER ARG IS AN
ARRAY REFERENCE, THAT ARG SHOULD BE ARG2 IF POSSIBLE*****)%
BEGIN
IF .ARG1NODE[OPRCLS] EQL ARRAYREF
OR
.CMPLX1 GTR .CMPLX2
THEN
%(***IF NEITHER ARG IS AN ARRAYREF NOR A DATA ITEM,
LET ARG2 BE THE ARG OF GREATER COMPLEXITY***)%
BEGIN
IF EXCHARGS(.CNODE)
THEN SWPARGDATA;
END;
END;
END;
%(***IF 1ST ARG IS NOT A SUBEXPRESSION WHOSE EVALUATION WILL LEAVE A RESULT
IN A REGISTER, THEN TRY TO MAKE 1ST ARG BE A VARIABLE WHOSE VALUE MIGHT
BE LEFT IN A REG FROM EXECUTION OF A PRECEEDING STMNT***)%
IF .ARG1NODE[OPRCLS] EQL DATAOPR !IF ARG1 IS A VAR OR CONST
THEN
BEGIN
IF SAVREGCONTAINING(.ARG1NODE) !IF CAN LEAVE ARG1 IN A REG FROM A
THEN BEGIN END ! PRECEEDING STMNT, DO SO
ELSE !OTHERWISE,
IF .ARG2NODE[RGCANDFLG] !IF ARG2 CAN BE LEFT IN A REG BY
AND NOT .CNODE[MEMCMPFLG]
THEN ! A PRECEEDING STMNT,
BEGIN
IF EXCHARGS(.CNODE) !IF CAN SWAP THE ARGS, DO SO
THEN
BEGIN
SWPARGDATA;
SAVREGCONTAINING(.ARG1NODE); !SAVE THE REG CONTAINING
! THE NEW ARG1
END;
END
END
ELSE
%(***
IF ARG1 IS AN ARRAYREF OR COMMON SUB OR ARG1 RETURNS ITS
VALUE IN THE FUNCTION RETURN REGISTER, CHECK IF ARG2 IS
ALSO A REGISTER AND, IF SO, PERFORM THE
CALCULATION IN THE REGISTER FOR ARG2
***)%
IF .ARG1NODE[OPRCLS] EQL ARRAYREF
OR .ARG1NODE[OPRCLS] EQL CMNSUB
OR
BEGIN !ARG1 RETURNING VALUE IN REGISTER 0?
.ARG1NODE[ALCRETREGFLG] AND
.ARG1NODE[INREGFLG] AND
.ARG1NODE[TARGTAC] EQL RETREG
END
THEN
BEGIN
IF .ARG2NODE[RGCANDFLG] !HENCE IF ARG2 WAS LEFT IN A REG
AND NOT .CNODE[MEMCMPFLG]
THEN ! BY A PRECEEDING STMNT
BEGIN
IF EXCHARGS(.CNODE) !IF CAN SWAP THE ARGS, DO SO
THEN
BEGIN
SWPARGDATA;
SAVREGCONTAINING(.ARG1NODE); !SAVE THE REG CONTAINING
! THE NEW ARG1
END
END
END;
%(***IF ARE COMPUTING TO MEMORY AND THE 1ST ARG IS A SIMPLE VAR OR CONST, THEN THAT
VAR OR CONST CAN BE LEFT IN A REG AFTER THIS STMNT IS EVALUATED**)%
IF .CNODE[MEMCMPFLG] AND .CNODE[A1VALFLG]
THEN ADDREGCANDATE(.ARG1NODE,.CNODE);
IF .CMPLX1 LEQ .CMPLX2
THEN
CNODE[RVRSFLG]_1;
%(***CHECK WHETHER THE VAL OF THE ARG COMPUTED FIRST WILL
BE LEFT IN "RETREG" AND THEN CLOBBERRED BY COMPUTATION
OF THE ARG THAT IS COMPUTED SECOND.
IF SO, UNDO THE ASSIGNMENT OF THAT VAL TO "RETREG"
********)%
IF NOT .CNODE[A1VALFLG] AND NOT .CNODE[A2VALFLG]
THEN
BEGIN
IF .CNODE[RVRSFLG]
THEN
%(***IF ARG2 IS EVALUATED FIRST***)%
BEGIN
IF .ARG2NODE[ALCRETREGFLG] AND .ARG1NODE[FNCALLSFLG]
THEN
BEGIN
ARG2NODE[ALCRETREGFLG]_0;
ARG2NODE[A1SAMEFLG]_0;
ARG2NODE[A2SAMEFLG]_0; !(NOTE THAT ARG-SAME-FLGS
! COULD ONLY BE SET AT THIS
! POINT DUE TO ALCRETREG
ARG2NODE[INREGFLG]_0;
END;
END
ELSE
%(***IF ARG1 IS EVALUATED FIRST***)%
BEGIN
IF .ARG1NODE[ALCRETREGFLG] AND .ARG2NODE[FNCALLSFLG]
THEN
BEGIN
ARG1NODE[ALCRETREGFLG]_0;
ARG1NODE[A1SAMEFLG]_0;
ARG1NODE[A2SAMEFLG]_0;
ARG1NODE[INREGFLG]_0;
END;
END;
END;
%(****IF ARG1 WILL BE COMPUTED INTO "RETREG" (FN RETURN REGISTER) THEN
WOULD LIKE TO COMPUTE PARENT IN RETREG ALSO.*******)%
IF NOT .CNODE[A1VALFLG] AND .ARG1NODE[ALCRETREGFLG]
AND .ARG1NODE[INREGFLG] AND .ARG1NODE[TARGTAC] EQL RETREG !(FOR RELATIONALS, "ALCRETREGFLG"
! INDICATES THAT THE COMPAR IS DONE
! IN RETREG, NOT THAT THE VAL IS LEFT THERE
THEN
%(***IF VAL OF ARG1 WILL BE LEFT IN "RETREG"***)%
BEGIN
IF .CNODE[OPRCLS] EQL RELATIONAL
THEN
CNODE[TARGAUX]_RETREG
ELSE
BEGIN
CNODE[TARGTAC]_RETREG;
CNODE[INREGFLG]_1;
END;
CNODE[ALCRETREGFLG]_1;
CNODE[A1SAMEFLG]_1;
END;
%(***IF CMPLX1 IS STILL 0 (AFTER HAVE ATTEMPTED TO SWAP ARGS), TREAT IT AS
IF IT WERE 1 (SINCE IT MUST BE LOADED INTO A REG TO PERFORM THE OPERATION***)%
IF .CMPLX1 EQL 0 THEN CMPLX1_1;
%(***RETURN THE COMPLEXITY OF CNODE - THIS VALUE IS EQUAL
TO THE MAXIMUM OF THE COMPLEXITY OF ARG1(CMPLX1) AND THE
COMPLEXITY OF ARG2 (CMPLX2), UNLESS THE TWO ARE EQUAL, IN
WHICH CASE IT IS ONE GREATER THAN THE VAL OF THE COMPLEXITY
OF THE 2 ARGS
*********)%
RETVAL _
BEGIN
IF .CMPLX1 EQL .CMPLX2
THEN
.CMPLX1+1
ELSE
BEGIN
IF .CMPLX2 GTR .CMPLX1
THEN
.CMPLX2
ELSE
.CMPLX1
END
END;
%(*** IF ARG1 IS DOUBLE PREC ARRAYREF FOR KA10 AND
ARG2 HAS NON-ZERO COMPLEXITY, THEN PARENT MUST
HAVE AT LEAST COMPLEXITY 3 ***)%
%622% ! COMPLEX ARRAY REF NEEDS 3 REGS ALSO!
%622% IF .ARG1NODE[OPRCLS] EQL ARRAYREF
%622% THEN IF .ARG1NODE[VALTYPE] EQL COMPLEX
%622% THEN IF .CMPLX2 NEQ 0
%622% THEN IF .RETVAL LSS 3
%622% THEN RETVAL _ 3;
RETURN .RETVAL;
END; ! of CMPLA
GLOBAL ROUTINE CMARGS=
%(***************************************************************************
ROUTINE TP PERFORM COMPLEXITY-WALK PROCESSING FOR THE 2 ARGS
UNDER THE NODE POINTED TO BY THE GLOBAL "TREEPTR".
IF EITHER OF THE ARGS HAS "FNCALLSFLG" SET, SETS IT IN THE PARENT.
IF EITHER OF THE ARGS HAS "RESRFFLG" SET, SETS IT IN THE PARENT.
IF EITHER ARG IS A CONSTANT, DECIDES WHETHER TO USE IT IMMEDIATE MODE,
OR ALLOCATE CORE FOR IT
***************************************************************************)%
BEGIN
LOCAL PEXPRNODE ARG1NODE:ARG2NODE:CNODE;
CNODE_.TREEPTR;
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
%(*****COMPUTE COMPLEXITY OF 1ST ARG******)%
IF NOT .CNODE[A1VALFLG]
THEN
BEGIN
TREEPTR_.CNODE[ARG1PTR];
SETCOMPLEXITY();
END;
%(*****COMPUTE COMPLEXITY OF 2ND ARG*****)%
IF NOT .CNODE[A2VALFLG]
THEN
BEGIN
TREEPTR_.CNODE[ARG2PTR];
SETCOMPLEXITY();
END;
%(***IF EITHER ARG IS THE VAR INTO WHICH THE RESULT OF THIS ASSIGNMENT IS
TO BE STORED, SET A FLAG IN THE PARENT***)%
IF .ARG1NODE EQL .RESNAME OR .ARG2NODE EQL .RESNAME THEN CNODE[RESRFFLG]_1;
%(***IF EITHER ARG IS A CONSTANT- THEN IF IT IS IMMED SIZE, SET IMMEDFLG,
IF NOT, ALLOCATE CORE FOR IT*****)%
IF .ARG1NODE[OPR1] EQL CONSTFL
THEN
PRCNSTARG(.CNODE,.ARG1NODE,TRUE);
IF .ARG2NODE[OPR1] EQL CONSTFL
THEN
PRCNSTARG(.CNODE,.ARG2NODE,FALSE);
%(***KEEP FLAGS FOR "FNCALL PRESENT SOMEWHERE UNDER THIS NODE"
AND "REF TO RESULT VARIABLE PRESENT SOMEWHER UNDER THIS NODE"*****)%
IF .ARG1NODE[OPRCLS] NEQ DATAOPR
THEN
BEGIN
IF .ARG1NODE[FNCALLSFLG] THEN CNODE[FNCALLSFLG]_1;
IF .ARG1NODE[RESRFFLG] THEN CNODE[RESRFFLG]_1;
END;
IF .ARG2NODE[OPRCLS] NEQ DATAOPR
THEN
BEGIN
IF .ARG2NODE[FNCALLSFLG] THEN CNODE[FNCALLSFLG]_1;
IF .ARG2NODE[RESRFFLG] THEN CNODE[RESRFFLG]_1;
END;
END; ! of CMARGS
GLOBAL ROUTINE EXPTOFNCALL= ![1505] Reformatted by AHM
BEGIN
! Transforms an exponentiation node into a function call node. Called
! with the global TREEPTR pointing to the node to be transformed.
REGISTER
PEXPRNODE FNNMENTRY, ! Points to the function name STE
PEXPRNODE ARG2NODE, ! Points to the RH exponentiation operand
ARGUMENTLIST LST; ! Points to the arg list being created
! Tables of routine names to be called for exponentiation
BIND
IEXPFNTBL= PLIT ( ! INTEGER exponent, non G-floating
SIXBIT 'EXP1.', !INTEGER**INTEGER
SIXBIT 'EXP2.', !REAL**INTEGER
SIXBIT 'DEXP2.', !DOUBLE-PREC**INTEGER
SIXBIT 'CEXP2.' ), !COMPLEX**INTEGER
%761% GIEXPFNTBL= PLIT ( ! INTEGER exponent, G-floating
%761% SIXBIT 'EXP1.', !INTEGER**INTEGER
%761% SIXBIT 'EXP2.', !REAL**INTEGER
%761% SIXBIT 'GEXP2.', !DOUBLE-PREC**INTEGER
%761% SIXBIT 'CEXP2.' ), !COMPLEX**INTEGER
EXPFNTBL=PLIT ( ! Exponent of same type as base, non G-floating
SIXBIT 'EXP1.', !INTEGER**INTEGER
SIXBIT 'EXP3.', !REAL**REAL
SIXBIT 'DEXP3.', !DOUBLE-PREC**DOUBLE-PREC
SIXBIT 'CEXP3.' ), !COMPLEX**COMPLEX
%761% GEXPFNTBL=PLIT ( ! Exponent of same type as base, G-floating
%761% SIXBIT 'EXP1.', !INTEGER**INTEGER
%761% SIXBIT 'EXP3.', !REAL**REAL
%761% SIXBIT 'GEXP3.', !DOUBLE-PREC**DOUBLE-PREC
%761% SIXBIT 'CEXP3.' ); !COMPLEX**COMPLEX
! Get core to hold the arg list
NAME<LEFT> = ARGLSTSIZE(2);
LST = CORMAN();
LST[ARGCOUNT] = 2; ! Say there are 2 arguments
LST[1,ARGNPTR] = .TREEPTR[ARG1PTR]; ! First one was ARG1PTR
LST[2,ARGNPTR] = ARG2NODE = .TREEPTR[ARG2PTR]; ! Second was ARG2PTR
LST[1,AVALFLG] = .TREEPTR[A1VALFLG]; ! Set the valflgs for
LST[2,AVALFLG] = .TREEPTR[A2VALFLG]; ! the 2 args
TREEPTR[OPRCLS] = FNCALL; ! Make the node a FNCALL node
TREEPTR[OPERSP] = LIBARY; ! (A library function)
TREEPTR[ARG2PTR] = .LST; ! Point to the argument list
TREEPTR[EXPFLAGS] = 0; ! Clear lots of flags
! Set ARG1 of the FNCALL to point to the symbol table entry for the
! function name for the function to be used. There are 2 sets of 2
! functions for each of the 4 main value types. One set is for normal
! double precision and the other is for G-floating DP. One function
! in each set is for that valtype raised to an integer power and the
! other is for that valtype raised to a power of the same valtype.
%761% IF .GFLOAT ! G-floating uses GEXP, not DEXP
%761% THEN IF .ARG2NODE[VALTP1] EQL INTEG1
%761% THEN ENTRY[0] = .GIEXPFNTBL[.TREEPTR[VALTP1]]
%761% ELSE ENTRY[0] = .GEXPFNTBL[.TREEPTR[VALTP1]]
%761% ELSE IF .ARG2NODE[VALTP1] EQL INTEG1
%761% THEN ENTRY[0] = .IEXPFNTBL[.TREEPTR[VALTP1]]
%761% ELSE ENTRY[0] = .EXPFNTBL[.TREEPTR[VALTP1]];
NAME = IDTAB; ! Search the symbol table
TREEPTR[ARG1PTR] = FNNMENTRY = TBLSEARCH();
FNNMENTRY[OPERSP] = FNNAME
END; ! of EXPTOFNCALL
GLOBAL ROUTINE PRCNSTARG(PARNODE, CONSTNODE,A1CNSTFLG)=
%(***************************************************************************
TO PROCESS A CONSTANT ARG.
IF IT IS OF IMMED SIZE, SET IMMEDFLG IN THE PARENT.
IF NOT, ALLOCATE CORE FOR IT.
CALLED WITH THE ARGS
PARNODE - PTR TO THE PARENT NODE
CONSTNODE - PTR TO THE CONSTANT TABLE ENTRY FOR THE CONSTANT
A1CNSTFLG - FLAG FOR "THE CONSTANT NODE IS THE 1ST ARG UNDER PARENT"
***************************************************************************)%
BEGIN
MAP PEXPRNODE PARNODE:CONSTNODE;
%(***IF THE CONSTANT IS USED AS THE 2ND ARG OF AN OPERATION WHICH IS PERFORMED
BY MEANS OF A FN-CALL (IE EXPONENTIATION OR DOUBLE-PREC OPS ON KA10), THEN
MUST ALLOCATE CORE FOR THE CONSTANT***)%
IF USEFNCALL(PARNODE) AND NOT .A1CNSTFLG
THEN
ALOCONST(.CONSTNODE)
%(***IF THE CONSTANT IS NOT OF TYPE INTEGER OR TYPE LOGICAL, AND A BOOLEAN
OPERATOR IS BEING APPLIED TO IT, THEN MUST ALLOCATE CORE FOR IT*****)%
ELSE
IF .PARNODE[OPRCLS] EQL BOOLEAN AND .CONSTNODE[VALTP1] NEQ INTEG1
THEN ALOCONST(.CONSTNODE)
%(***IF CONSTANT IS IMMEDIATE SIZE, DO NOT ALLOCATE CORE FOR IT. INSTEAD, SET
IMMEDFLG IN THE PARENT
*****)%
ELSE
IF IMMEDCNST(CONSTNODE)
THEN
BEGIN
(IF .A1CNSTFLG THEN PARNODE[A1IMMEDFLG] ELSE PARNODE[A2IMMEDFLG])_1;
IF .CONSTNODE[CONST2] LSS 0 AND .CONSTNODE[VALTP1] EQL INTEG1
THEN
%(***IF THE CONSTANT IS A NEG INTEGER, USE A POSITIVE NUMBER NEGATED.***)%
BEGIN
IF .PARNODE[OPRCLS] EQL BOOLEAN THEN
%(***FOR BOOLEANS, USE THE 1S COMPLEMENT AND THE 'NOT'
VERSION OF THE INSTRUCTION.*******)%
BEGIN
IF .A1CNSTFLG !TO PICK UP ARG1 WITH"NOT"
THEN
BEGIN
PARNODE[A1NOTFLG]_NOT .PARNODE[A1NOTFLG];
PARNODE[ARG1PTR]_MAKECNST(.CONSTNODE[VALTYPE],0,NOT .CONSTNODE[CONST2]);
END
ELSE !TO OPERATE ON ARG2 WITH "NOT"
BEGIN
PARNODE[A2NOTFLG]_NOT .PARNODE[A2NOTFLG];
PARNODE[ARG2PTR]_
MAKECNST(.CONSTNODE[VALTYPE],0,NOT .CONSTNODE[CONST2]);
END;
END
ELSE
IF .PARNODE[OPRCLS] EQL STATEMENT
THEN
BEGIN
%(***FOR ASSIGNMENT STMNTS, IF RHS IS AN IMMED CONSTANT
WHEN NEGATED, THEN SET A2NEGFLG AND USE THE NEG***)%
IF .PARNODE[SRCID] EQL ASGNID
THEN
BEGIN
PARNODE[A2NEGFLG]_NOT .PARNODE[A2NEGFLG];
PARNODE[RHEXP]_MAKECNST(.CONSTNODE[VALTYPE],0,-.CONSTNODE[CONST2]);
END
ELSE CGERR(); !SHOULD NEVER CALL PRCNSTARG WITH
! ANY STMNT OTHER THAN ASSIGNMENT
END
ELSE
IF .A1CNSTFLG
THEN
BEGIN
PARNODE[A1NEGFLG]_NOT .PARNODE[A1NEGFLG];
PARNODE[ARG1PTR]_MAKECNST(.CONSTNODE[VALTYPE],0,-.CONSTNODE[CONST2]);
END
ELSE
BEGIN
PARNODE[A2NEGFLG]_NOT .PARNODE[A2NEGFLG];
PARNODE[ARG2PTR]_MAKECNST(.CONSTNODE[VALTYPE],0,-.CONSTNODE[CONST2]);
END;
END
END
ELSE
ALOCONST(.CONSTNODE);
END; ! of PRCNSTARG
GLOBAL ROUTINE CMPVBOOL=
%(***************************************************************************
ROUTINE PERFORMS COMPLEXITY WALK FOR A BOOLEAN WHOSE VALUE IS
TO BE COMPUTED.
***************************************************************************)%
BEGIN
LOCAL PEXPRNODE CNODE:ARG1NODE:ARG2NODE;
%(***FOR EQV AND XOR - TREAT SAME AS ARITH****)%
IF .TREEPTR[BOOLCLS] NEQ ANDORCLS THEN CMPLA()
ELSE
%(***IF VALTYPE OF THIS NODE IS "CONTROL" WILL NEED 1 REG TO HOLD THE VAL
IN ADDITION TO THE NUMBER OF REGS NEEDED FOR THE CONTROL BOOLEAN IF
IT WERE USED STRICTLY FOR CONTROL PURPOSES****)%
IF .TREEPTR[VALTYPE] EQL CONTROL
THEN CMPLBL() + 1
ELSE
BEGIN
CNODE_.TREEPTR;
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
%(***IF ONE OF THE 2 ARGS HAS VALTYPE CONTROL (AND THE OTHER IS A MASK)
ALWAYS MAKE ARG1 BE THE MASK.
********)%
IF .ARG1NODE[VALTYPE] EQL CONTROL
THEN
BEGIN
EXCHARGS(.CNODE);
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
END;
%(***IF ONE ARG IS OF TYPE CONTROL, WILL INIT VAL OF BOOLEAN TO THE
OTHER ARG, THEN EVALUATE THE CONTROL ARG***)%
IF .ARG2NODE[VALTYPE] EQL CONTROL
THEN
BEGIN
%(***PERFORM COMPLEXITY WALK FOR THE 2 ARGS. PROPAGATE
FNCALLSFLG AND RESRFFLG UP FROM THE ARGS TO THE PARENT***)%
CMARGS();
%(***IF ARG1 IS COMPUTED INTO FN-RETURN-REG***)%
IF .ARG1NODE[OPRCLS] NEQ DATAOPR
AND .ARG1NODE[ALCRETREGFLG]
THEN
BEGIN
%(**IF COMP OF ARG2 WILL CLOBBER FN-RET-REG, THEN
MUST STORE ARG1 ELSEWHERE***)%
IF .ARG2NODE[FNCALLSFLG]
THEN
BEGIN
ARG1NODE[ALCRETREGFLG]_0;
ARG1NODE[A1SAMEFLG]_0;
ARG1NODE[INREGFLG]_0;
END
%(***OTHERWISE COMPUTE PARENT IN FN-RET REG***)%
ELSE
BEGIN
CNODE[ALCRETREGFLG]_1;
CNODE[A1SAMEFLG]_1;
CNODE[INREGFLG]_1;
CNODE[TARGTAC]_RETREG;
END;
END;
SAVREGCONTAINING(.ARG1NODE); !IF BB ALLOCATOR CAN LEAVE VAL OF ARG1 IN A REG
! IN SOME PREV STMNT, IT SHOULD DO SO
%(***COMPLEXITY OF CNODE IS MAX OF (1+CMPLX OF ARG2) AND
CMPLX OF ARG1 ***)%
IF .ARG1NODE[COMPLEXITY] GTR .ARG2NODE[COMPLEXITY]
THEN .ARG1NODE[COMPLEXITY]
ELSE .ARG2NODE[COMPLEXITY] + 1
END
ELSE
%(***FOR AND OR OR WHEN NEITHER ARG HAS TYPE CONTROL, TREAT LIKE ARITH***)%
CMPLA()
END
END; ! of CMPVBOOL
GLOBAL ROUTINE CMPLBL=
%(***************************************************************************
ROUTINE TO COMPUTE THE COMPLEXITY OF A CONTROL-TYPE BOOLEAN
CALLED WITH THE GLOBAL TREEPTR POINTING TO THE NODE
WHOSE COMPLEXITY IS TO BE RETURNED
***************************************************************************)%
BEGIN
LOCAL PEXPRNODE CNODE:ARG1NODE:ARG2NODE;
LOCAL CMPLX1,CMPLX2; !COMPLEXITY OF ARG1 AND ARG2
CNODE_.TREEPTR; !PTR TO THE NODE BEING PROCESSED
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
%(****FOR 1ST ARG**************************************)%
TREEPTR_.ARG1NODE;
%(****ARGS OF A CONTROL-TYPE BOOLEAN CAN BE EITHER CONTROL-TYPE
BOOLEANS, OR RELATIONALS************************)%
IF .ARG1NODE[OPRCLS] EQL RELATIONAL
THEN
%(****FOR A RELATIONAL USED FOR CONTROL PURPOSES ONLY***)%
ARG1NODE[COMPLEXITY]_(CMPLX1_CMPLREL())
ELSE
BEGIN
IF .ARG1NODE[OPRCLS] EQL BOOLEAN
THEN
%(****IF A SUBNODE IS A BOOLEAN, IT MUST BE A CONTROL-TYPE BOOLEAN****)%
ARG1NODE[COMPLEXITY]_(CMPLX1_CMPLBL())
ELSE
CGERR(5)
END;
%(****FOR 2ND ARG**************************************)%
TREEPTR_.ARG2NODE;
%(****ARGS OF A CONTROL-TYPE BOOLEAN CAN BE EITHER CONTROL-TYPE
BOOLEANS, OR RELATIONALS************************)%
IF .ARG2NODE[OPRCLS] EQL RELATIONAL
THEN
%(****FOR A RELATIONAL USED FOR CONTROL PURPOSES ONLY***)%
ARG2NODE[COMPLEXITY]_(CMPLX2_CMPLREL())
ELSE
BEGIN
IF .ARG2NODE[OPRCLS] EQL BOOLEAN
THEN
%(****IF A SUBNODE IS A BOOLEAN, IT MUST BE A CONTROL-TYPE BOOLEAN****)%
ARG2NODE[COMPLEXITY]_(CMPLX2_CMPLBL())
ELSE
CGERR(5)
END;
%(****SET THE FLAG "FNCALLSFLG" IN THE PARENT, IF ANY FNCALLS ARE UNDER
ANY OF THE ARGS****)%
%(****SET THE FLAG "RESRFFLG" IN THE PARENT IF REF TO LOC OF FINAL RESULT
OCCURS UNDER EITHER ARG*****)%
IF .ARG1NODE[FNCALLSFLG] OR .ARG2NODE[FNCALLSFLG] THEN CNODE[FNCALLSFLG]_1;
IF .ARG1NODE[RESRFFLG] OR .ARG2NODE[RESRFFLG] THEN CNODE[RESRFFLG]_1;
%(****FOR A CONTROL-TYPE BOOLEAN, COMPLEXITY IS EQUAL TO MAX
OF COMPLEXITY OF THE 2 ARGS**********************)%
IF .CMPLX2 GTR .CMPLX1
THEN
CMPLX1_.CMPLX2;
CNODE[COMPLEXITY] _.CMPLX1;
RETURN .CMPLX1
END; ! of CMPLBL
GLOBAL ROUTINE CMPLREL=
%(****************************************************************************
ROUTINE TO COMPUTE THE COMPLEXITY OF A RELATIONAL.
COMPUTES THE NUMBER OF REGISTERS NEEDED IF THE REL IS USED
FOR CONTROL PURPOSES ONLY.
CALLED WITH THE GLOBAL TREEPTR POINTING TO THE NODE FOR
THE RELATIONAL.
****************************************************************************)%
BEGIN
OWN CMPLX1;
LOCAL PEXPRNODE CNODE:ARG1NODE: ARG2NODE;
CNODE_.TREEPTR;
%(***USE SAME BASIC ALGORITHM FOR COMPLEXITY AS IS USED FOR ARITH NODES***)%
CMPLX1_CMPLA();
ARG1NODE_.CNODE[ARG1PTR]; !AFTER CMPLA, GET VALS OF ARG1PTR AND ARG2PTR
ARG2NODE_.CNODE[ARG2PTR];
CNODE[INREGFLG]_0; !CMPLA WOULD HAVE SET "INREGFLG" IF IT ALLOCATED
! THIS NODE TO BE COMPUTED IN FN-RET REG -
! BUT FOR A RELATIONAL, THE COMPAR
! IS PERF IN A REG, BUT THE VAL MIGHT BE LEFT
! IN A TEMP
%(***IF ARGS ARE DOUBLE-WORD, THEN NEED TWICE AS MANY REGS AS CMPLX1 INDICATES ***)%
IF .ARG1NODE[DBLFLG] THEN
BEGIN
CMPLX1_.CMPLX1^1;
PAIRMODE_TRUE !IF THE OPERANDS OF THE RELATIONAL ARE DP OR COMPLEX VARS
! WILL NEED A REG PAIR TO DO THE COMPARISON
END;
%(***IF ARG2 IS A REAL OR COMPLEX IMMED CONSTANT,
WILL HAVE TO ALLOCATE CORE FOR IT (SINCE
HAVE NO COMPARE IMMED INSTRUCTION FOR REALS) HANCE IF ONE ARG IS
REAL IMMED AND THE OTHER IS A VAR , LET ARG1 BE THE CONST ARG.
IF BOTH ARGS ARE REAL IMMED(POSSIBLE ONLY IF P2SKEL NOT USED),
ALLOCATE CORE FOR ARG2****)%
IF .CNODE[A2IMMEDFLG]
THEN
BEGIN
IF (.ARG2NODE[OPERATOR] EQL REALCONST OR .ARG2NODE[OPERATOR] EQL CPLXCONST)
AND (.ARG2NODE[CONST1] NEQ 0) !CAN USE CAI FOR ZERO
THEN
BEGIN
%(***IF ARG1 IS AN EXPRESSION (WHOSE VAL WILL PROBABLY BE LEFT IN A REG)
OR IS A VARIABLE WHOSE VAL CAN BE LEFT IN A REG BY A PREV STMNT
OR IF ARG1 IS ALSO AN IMMED CONSTANT,
ALLOCATE CORE FOR ARG2
********)%
IF .CNODE[A1IMMEDFLG] !IF ARG1 IS AN IMMED CONST
OR
(.ARG1NODE[OPRCLS] NEQ ARRAYREF !ARG1 NOT AN ARRAY REF
AND
NOT (.ARG1NODE[OPRCLS] EQL DATAOPR !ARG1 NOT A VAR THAT
AND NOT .ARG1NODE[RGCANDFLG]) ! COULD NOT HAVE BEEN LEFT IN A REG
)
THEN
BEGIN
%(***MUST ALLOCATE CORE FOR ARG2***)%
ALOCONST(.ARG2NODE);
CNODE[A2IMMEDFLG]_0;
END
%(***IF ARG1 IS A VAR THAT COULD NOT HAVE BEEN LEFT IN A REG BY A PREV STMNT
OR IF ARG1 IS AN ARRAYREF (IE IF ARG1 HAS TO BE LOADED INTO
A REG) AND IF ARG1 IS NOT ALSO AN IMMED REAL CONST,
EXCHANGE THE 2 ARGS***)%
ELSE
EXCHARGS(.CNODE)
END;
END;
%(***CANNOT GENERATE CODE FOR A RELATIONAL WHICH HAS A NEGFLG OVER
ARG2. GET RID OF ANY A2NEGFLG BY:
A LT -B = -A GT B
A LEQ -B = -A GEQ B
A EQ -B = -A EQ B
ETC
*****)%
IF .CNODE[A2NEGFLG]
THEN
BEGIN
CNODE[A1NEGFLG]_NOT .CNODE[A1NEGFLG];
CNODE[A2NEGFLG]_0;
IF NOT EQREL(.CNODE[OPERSP])
THEN CNODE[OPERSP]_REVREL(.CNODE[OPERSP])
END;
%(***IF A1NEGFLG IS NOW SET AND ARG1 IS AN EXPRESSION, TRY TO PROPAGATE
THE NEGATIVE OVER ARG1
*******)%
IF .CNODE[A1NEGFLG] AND NOT .CNODE[A1VALFLG]
THEN
BEGIN
IF PROPNEG(.CNODE[ARG1PTR]) THEN CNODE[A1NEGFLG]_0;
END;
%(***IF ARG1 IS A VAR OR CONST, ADD IT TO THE SET
OF VARS WHOSE VALS ARE LEFT IN REGS BY THE EVAL OF STMNTS***)%
IF .CNODE[A1VALFLG]
THEN
BEGIN
%(**IF BOTH ARGS ARE VARS/CONSTS THEN PUT ARG2 IN THE SET OF VARS
WHOSE VALS CAN BE LEFT IN REGS**)%
IF .CNODE[A2VALFLG]
THEN
BEGIN
%(**ONLY PUT ARG2 INTO THE SET OF POTENTIAL REG VARS IF
1. ARG1 IS A CONST OR VAR (NOT A CSB)
2. ARG1 WILL NOT BE AVAILABLE IN A REG FROM SOME
EARLIER STMNT
*****)%
ARG1NODE_.CNODE[ARG1PTR];
IF .ARG1NODE[OPRCLS] EQL DATAOPR
AND NOT .ARG1NODE[RGCANDFLG]
THEN ADDREGCANDATE(.CNODE[ARG2PTR],.CNODE);
END;
%(***ADD ARG1 TO SET OF POTENTIAL REG-VARS***)%
ADDREGCANDATE(.CNODE[ARG1PTR],.CNODE);
END;
RETURN .CMPLX1;
END; ! of CMPLREL
ROUTINE CMPLCONCAT=
BEGIN
!***************************************************************
! Compute the complexity of a concatenation node by examining
! its list of arguments. Called with the global treeptr
! pointing to the concatenation node.
!***************************************************************
%1474% ! Written by TFV on 12-Feb-82
BIND INCONCAT = TRUE; ! Flag for CMPFNARGS. It indicates that
! the first argument should be ignored
LOCAL ARGUMENTLIST ARGLST;
LOCAL CMPLX1;
LOCAL PEXPRNODE CNODE;
LOCAL PEXPRNODE ARGNODE;
FNREF = TRUE; ! Set global flag indicating that this statement
! includes a function call
TREEPTR[FNCALLSFLG] = 1; ! Set flag in statement node for
! function calls occur under
! this node
CNODE = .TREEPTR; ! Save pointer to current node
! Complexity will be the maximum of complexities of the
! arguments in the argument list. For concatenations, the first
! argument is not set up until allocation.
CMPLX1 = CMPFNARGS(.TREEPTR[ARG2PTR],.TREEPTR[DBLFLG],INCONCAT);
! Determine whether any argument under this call is equal to the
! left hand side of this assignment or contains any reference to
! it.
ARGLST = .CNODE[ARG2PTR];
INCR CT FROM 1 TO .ARGLST[ARGCOUNT] BY 1
DO
BEGIN ! Walk down the argument list
ARGNODE = .ARGLST[.CT,ARGNPTR];
IF .ARGNODE[OPRCLS] EQL DATAOPR
THEN
BEGIN
IF .ARGNODE EQL .RESNAME THEN CNODE[RESRFFLG] = 1;
END
ELSE IF .ARGNODE[RESRFFLG] THEN CNODE[RESRFFLG] = 1;
END;
RETURN .CMPLX1;
END; ! of CMPLCONC
GLOBAL ROUTINE CMPLFNCALL=
BEGIN
!***************************************************************
! Compute the complexity of a function call by examining its
! list of arguments. Called with the global TREEPTR pointing to
! the function call node.
!***************************************************************
BIND NOTINCONCAT = FALSE; ! Flag for CMPFNARGS. It means
! that the first argument must
! be processed.
LOCAL ARGUMENTLIST ARGLST;
LOCAL CMPLX1;
LOCAL PEXPRNODE CNODE;
LOCAL PEXPRNODE ARGNODE;
! Set global flag indicating that this statment includes a
! function call. Set the flag in the node also.
FNREF = TRUE;
TREEPTR[FNCALLSFLG] = 1;
%1422% IF .TREEPTR[VALTYPE] NEQ CHARACTER
%1422% THEN
%1422% BEGIN ! Non-character functions return the result in AC0, AC1
TREEPTR[ALCRETREGFLG] = 1;
TREEPTR[TARGTAC] = RETREG;
TREEPTR[INREGFLG] = 1;
TREEPTR[TARGADDR] = RETREG;
%1422% END; ! Non-character functions return the result in AC0, AC1
! If no arguments then complexity is 0
IF .TREEPTR[ARG2PTR] EQL 0 THEN RETURN 0;
CNODE = .TREEPTR; ! Setup pointer to the node
! Complexity will be the maximum of the complexities of the
! elements of the argument list
%1474% CMPLX1 = CMPFNARGS(.TREEPTR[ARG2PTR],.TREEPTR[DBLFLG],NOTINCONCAT);
! Determine whether any argument under this call is equal to the
! left hand side of this assignment or contains a reference to
! it.
ARGLST = .CNODE[ARG2PTR];
INCR CT FROM 1 TO .ARGLST[ARGCOUNT]
DO
BEGIN ! Walk down the argument list
ARGNODE = .ARGLST[.CT,ARGNPTR];
IF .ARGNODE[OPRCLS] EQL DATAOPR
THEN
BEGIN
IF .ARGNODE EQL .RESNAME THEN CNODE[RESRFFLG] = 1;
END
ELSE
IF .ARGNODE[RESRFFLG] THEN CNODE[RESRFFLG] = 1;
END; ! Walk down the argument list
RETURN .CMPLX1;
END; ! of CMPLFNCALL
GLOBAL ROUTINE CMPFNARGS(ARLISTT,PARDBLFLG,INCONCAT)=
BEGIN
!***************************************************************
! Compute the complexity of an argument list. Used for
! functions, subroutine calls, and concatenations. PARDBLFLG is
! true iff the function had a double word value and hence
! allocation at the parent level was done in double word mode.
! The flag INCONCAT is true if this is called from CMPLCONCAT.
! In that case the first argument is ignored since it is not set
! up until allocation.
!***************************************************************
%1474% REGISTER FIRSTARG; ! The first argument to examine
MAP ARGUMENTLIST ARLISTT;
LOCAL CMPLMAX, CMPL1;
LOCAL PEXPRNODE ARGNODE;
CMPLMAX = 0;
%1474% ! Decide which argument is the first to examine
%1474% IF .INCONCAT THEN FIRSTARG = 2 ELSE FIRSTARG = 1;
%1474% INCR CT FROM .FIRSTARG TO .ARLISTT[ARGCOUNT] BY 1
DO
BEGIN ! Walk down the argument list
ARGNODE = .ARLISTT[.CT,ARGNPTR]; ! Get the argument
TREEPTR = .ARGNODE;
! If this argument is a constant, set the flag to allocate
! memory for that constant
IF .ARGNODE[OPR1] EQL CONSTFL
THEN
BEGIN
ALOCONST(.TREEPTR);
CMPL1 = 0
END
ELSE
IF NOT .ARLISTT[.CT,AVALFLG]
THEN
BEGIN
! Compute the complexity of the argument
CMPL1 = SETCOMPLEXITY();
! Check for an argument that requires a double
! word computation. If parent was not also in
! double word mode, must double the size of the
! number of registers indicated
IF .ARGNODE[DBLFLG] AND NOT .PARDBLFLG
THEN CMPL1 = .CMPL1^1
ELSE
! If parent is in double word mode and the
! argument is in single word mode, divide the
! complexity in half
IF .PARDBLFLG AND NOT .ARGNODE[DBLFLG]
THEN CMPL1 = (.CMPL1+1)^(-1);
! Check if the argument is a formal array
IF ARRNARGBLK(ARLISTT[.CT,ARGNPTR],ARLISTT[.CT,AVALFLG])
THEN CMPL1 = 0;
END
ELSE CMPL1 = 0;
IF .CMPL1 GTR .CMPLMAX THEN CMPLMAX = .CMPL1;
END; ! Walk down the argument list
RETURN .CMPLMAX
END; ! of CMPFNARGS
GLOBAL ROUTINE CMPTPCNV=
%(***************************************************************************
TO COMPUTE THE COMPLEXITY OF A TYPE CONVERSION NODE.
IF THE CONVERSION IS BETWEEN SINGLE-WORD AND DOUBLE-WORD VALUES,
MUST ADJUST THE COMPLEXITY USED FOR NODES BELOW THIS ONE.
IF THE CONVERSION IS BETWEEN FIXED AND FLOAT ON THE KA10, WILL NEED AN
EXTRA REG.
***************************************************************************)%
BEGIN
LOCAL PEXPRNODE CNODE:ARGNODE;
OWN CMPLX1;
CNODE_.TREEPTR;
ARGNODE_.CNODE[ARG2PTR];
%(***GET COMPLEXITY OF THE ARG***)%
IF .CNODE[A2VALFLG]
THEN
BEGIN
CMPLX1_0;
%(***IF ARG IS EQUAL TO THE VARIABLE ON THE LHS OF THIS ASSIGNMENT
SET A FLG*****)%
IF .CNODE[ARG2PTR] EQL .RESNAME
THEN
CNODE[RESRFFLG]_1;
%(***IF THE ARG UNDER THIS NODE COULD HAVE BEEN LEFT IN A REG
BY THE EVAL OF A PRECEEDING STMNT, DO SO***)%
SAVREGCONTAINING(.ARGNODE);
END
ELSE
BEGIN
ARGNODE_.CNODE[ARG2PTR];
TREEPTR_.CNODE[ARG2PTR];
CMPLX1_SETCOMPLEXITY();
%(***IF VAL OF ARG IS COMPUTED INTO RETREG,
COMPUTE VAL OF PARENT INTO RETREG**)%
SNGARGPROP(.CNODE,.ARGNODE);
END;
%(***IF ARG IS A CONSTANT, MUST ALLOCATE CORE FOR IT (THIS WILL ONLY
OCCUR IF CALLED THE TYPE CONV ROUTINE EXPLICITLY)***)%
IF .ARGNODE[OPR1] EQL CONSTFL
THEN
ALOCONST(.ARGNODE);
%(***UNLESS NO CONVERSION CODE HAS TO BE GENERATED,
AT LEAST 1 REGISTER WILL BE NEEDED TO PERFORM
THE CONVERSION IN
*******)%
IF NOT NOCNV(CNODE)
THEN
BEGIN
IF .CMPLX1 EQL 0
THEN CMPLX1_1;
END;
%(***CHECK FOR CHANGE IN PRECISION ACROSS THIS NODE***)%
IF .CNODE[DBLFLG] AND NOT .CNODE[SDBLFLG]
THEN
%(***IF NODE BELOW IS SINGLE-WD AND THIS NODE
IS DOUBLE-WD***)%
CMPLX1_(.CMPLX1+1)^(-1)
ELSE
IF NOT .CNODE[DBLFLG] AND .CNODE[SDBLFLG]
THEN
%(***IF NODE BELOW IS DOUBLE-WD AND THIS NODE
IS SINGLE-WD***)%
CMPLX1_.CMPLX1^1;
RETURN .CMPLX1;
END; ! of CMPTPCNV
GLOBAL ROUTINE CMPLXARRAY=
%(***************************************************************************
COMPUTE THE COMPLEXITY OF AN ARRAY REFERENCE.
MUST GET THE VALUE OF THE OFFSET INTO A REGISTER (UNLESS IT IS CONSTANT).
THEREFORE NEED AS MANY REGS AS ARE NEEDED TO COMPUTE THAT VAL,
OR 1 REG IF THAT VAL REQUIRES NO COMPUTATION BUT IS NOT CONSTANT (IE IS
A SCALER).
SET UP THE TARGET WD OF THIS ARRAYREF NODE SO THAT THE RIGHT-HALF
CONTAINS THE CONSTANT PART OF THE REFERENCE TO THIS ELEMENT (IE THE
SUM OF THE ADDRESS OF THE ARRAY BASE WITH ANY CONSTANTS INVOLVED IN THE OFFSET
CALCULATION. IN ORDER TO DO THIS MUST WALK DOWN THE N-ARY SUM
THAT IS THE ADDRESS CALCULATION, TO GET ANY CONSTANT TERM (WHICH
THE CANONICALIZER WILL HAVE LEFT AT BOTTOM LEFT).
NOTE THAT THE TARGET WORD ALREADY CONTAINS ANY CONSTANT TERMS THAT
WERE DETECTED AT THE TIME THAT THE ADDRESS CALCULATION WAS EXPANDED.
THIS ROUTINE IS CALLED WITH THE GLOBAL TREEPTR POINTING TO THE
ARRAYREF NODE TO BE PROCESSED.
***************************************************************************)%
BEGIN
OWN T1;
OWN AADDR;
OWN CMPLX1;
OWN PEXPRNODE CONSTTERM; !EVENTUALLY WILL BE SET TO PT TO THE
! CONSTANT TERM IN THE ADDRESS CALC
OWN PEXPRNODE PAROFCONST; !PTR TO PARENT OF CONSTTERM
OWN PEXPRNODE GPOFCONST; !PTR TO PARENT OF "PAROFCONST"
LOCAL PEXPRNODE CNODE:NAME:ADDRNODE;
NAME_.TREEPTR[ARG1PTR];
ADDRNODE_.TREEPTR[ARG2PTR];
CNODE_.TREEPTR;
%(***IF THE ARRAY NAME IS IDENTICAL TO THE ARRAY NAME ON LEFT HAND
SIDE OF ASSIGNMENT OR THE ADDRNODE IS IDENTICAL TO A SIMPLE VAR
ON THE LEFT HAND SIDE OF THE ASSIGNMENT, SET FLAGS
INDICATING THAT THERE IS A REFERENCE TO LHS UNDER THIS NODE***)%
IF (.NAME EQL .RESNAME) OR (.ADDRNODE EQL .RESNAME) THEN TREEPTR[RESRFFLG]_1;
%1253% IF .NAME[VALTYPE] NEQ CHARACTER
%1253% THEN
BEGIN ! NON-CHARACTER
%(***FOR AN ARRAY WHICH IS NOT A FORMAL, ADD THE BASE ADDRESS OF
THE ARRAY INTO THE CONSTANT PART OF THE ADDRESS CALCULATION***)%
AADDR_ (IF .NAME[FORMLFLG]
THEN 0
ELSE .NAME[IDADDR] );
%(***IF THERE IS NO ADDRESS CALCULATION TO BE DONE (ADDR IS A CONSTANT WHICH
WAS DETECTED AT TIME OF EXPANSION OF THE ARRAY).
FILL IN CORRECT VAL FOR TARGET FIELD AND RETURN.
*******)%
IF .ADDRNODE EQL 0
THEN
BEGIN
T1_.AADDR + EXTSIGN( .TREEPTR[TARGADDR]);
TREEPTR[A2IMMEDFLG]_1;
TREEPTR[TARGADDR]_.T1;
RETURN 0
END;
%(***IF ADDRNODE IS A CONSTANT, THEN NO RUNTIME ADDRESS CALCULATION IS NECESSARY***)%
IF .ADDRNODE[OPR1] EQL CONSTFL
THEN
BEGIN
T1_.ADDRNODE[CONST2] + .AADDR + EXTSIGN( .TREEPTR[TARGADDR]);
TREEPTR[ARG2PTR]_0; !SET THE "VARIABLE-PART" OF THE ADDRESS CALC
! TO 0
TREEPTR[A2VALFLG]_1;
TREEPTR[A2IMMEDFLG]_1;
TREEPTR[TARGADDR]_.T1; !PUT THE CONSTANT PART OF THE ADDRESS INTO
! THE TARGET FIELD OF THE ARRAYREF NODE
RETURN 0
END;
IF .ADDRNODE[OPRCLS] EQL CMNSUB !IF THE VARIABLE PART OF THE ADDRESS IS A COMMON SUB
THEN ADDRNODE[CSSSFLG]_1; !SET FLAG INDICATING "THIS CS USED AS A SUBSCRIPT"
! (THIS WILL CAUSE IT TO GET PRIORITY FOR A REGISTER)
%(*****IF ADDRESS COMPUTATION IS A SUM, SEARCH DOWN THE N-ARY SUM
FOR THE CONSTANT TERM (WHICH THE CANONICALIZER WILL HAVE LEFT AT
BOTTOM LEFT). EXTRACT THIS TERM FROM THE TREE AND PUT IT IN THE TARGET FIELD.
*********)%
IF .ADDRNODE[OPR1] EQL ADDOPF
THEN
BEGIN
CONSTTERM_.ADDRNODE[ARG1PTR];
IF .CONSTTERM[OPR1] EQL CONSTFL
THEN
BEGIN
%(***ADD THE CONSTANT TERM INTO THE ADDRESS FIELD OF THE INSTR
(TRUNCATE TO 18 BITS IF NECESSARY)
AND REMOVE THE CONSTANT NODE FROM THE TREE***)%
T1_.AADDR + EXTSIGN( .TREEPTR[TARGADDR]) + .CONSTTERM[CONST2];
TREEPTR[TARGADDR]_.T1;
TREEPTR[A2FLGS]_RAISEFLGS(.TREEPTR[A2FLGS],.ADDRNODE[A2FLGS]);
TREEPTR[ARG2PTR]_.ADDRNODE[ARG2PTR];
ADDRNODE_.ADDRNODE[ARG2PTR];
END
ELSE
%(***IF LH OF TOP-LEVEL SUM IS ALSO A + NODE, SEARCH DOWN IT FOR
THE CONSTANT TERM*******)%
IF .CONSTTERM[OPR1] EQL ADDOPF
THEN
BEGIN
PAROFCONST_.CONSTTERM;
CONSTTERM_.CONSTTERM[ARG1PTR];
WHILE .CONSTTERM[OPR1] EQL ADDOPF
DO
(PAROFCONST_.CONSTTERM; CONSTTERM_.CONSTTERM[ARG1PTR]);
%(***IF THERE IS A CONSTANT-TERM, IT WILL BE THE FIRST NON-PLUS NODE
REACHED****)%
IF .CONSTTERM[OPR1] EQL CONSTFL
THEN
BEGIN
T1_.AADDR+EXTSIGN(.TREEPTR[TARGADDR])+.CONSTTERM[CONST2];
TREEPTR[TARGADDR]_.T1;
%(***REMOVE THE CONSTANT NODE FROM THE TREE,
LINKING ITS BROTHER UNDER ITS PARENT PLUS-NODE
DIRECTLY TO ITS
GRAND-PARENT PLUS-NODE***)%
GPOFCONST_.PAROFCONST[PARENT];
GPOFCONST[A1FLGS]_RAISEFLGS(.GPOFCONST[A1FLGS],
.PAROFCONST[A2FLGS]);
GPOFCONST[ARG1PTR]_.PAROFCONST[ARG2PTR];
END
ELSE
%(***IF THERE IS NO CONSTANT TERM, JUST ADD THE ARRAY BASE ADDRESS
INTO THE TARGET WD***)%
TREEPTR[TARGADDR]_.AADDR+EXTSIGN(.TREEPTR[TARGADDR]);
END
ELSE
TREEPTR[TARGADDR]_.AADDR+EXTSIGN(.TREEPTR[TARGADDR]);
END
ELSE
TREEPTR[TARGADDR]_.AADDR+EXTSIGN(.TREEPTR[TARGADDR]);
END ! NON-CHARACTER
%1253% ELSE
%1253% BEGIN ! [1253] CHARACTER
IF .ADDRNODE EQL 0 ! IF SUBSCRIPT IS CONSTANT AND HAS
THEN ! BEEN FOLDED INTO BASE (NYI),
RETURN 1; ! IT REQUIRES 1 REGISTER
IF .ADDRNODE[OPR1] EQL CONSTFL
THEN
PRCNSTARG(.TREEPTR,.ADDRNODE,FALSE);
END; ! [1253] CHARACTER
%(***IF THE VARIABLE PART OF THE ADDR IS A SINGLE VAR, THEN IF IT
COULD BE LEFT IN A REG EARLIER DO SO AND IF ITS NEEDED LATER THEN
LEAVE ITS REG ALONE AFTER EXECUTIOM OF THIS STMNT***)%
IF .TREEPTR[A2VALFLG]
THEN
BEGIN
SAVREGCONTAINING(.ADDRNODE); !SAVE THE REG FROM PREV REF
%1253% IF .NAME[VALTYPE] NEQ CHARACTER !IF NON-CHARACTER
THEN ADDREGCANDATE(.ADDRNODE,.TREEPTR); !IF NEED THE REG LATER, CAN USE IT
! FROM THIS REF
END;
%(***FIND THE NUMBER OF REGISTERS NECESSARY TO COMPUTE THE ADDRESS,
THE COMPLEXITY OF THE ARRAYREF NODE IS 1 IF 0 REGS ARE NEEDED, OTHERWISE
IT IS EQUAL TO THE NUMBER OF REGS NEEDED*****)%
IF .TREEPTR[A2VALFLG]
THEN CMPLX1_1
ELSE
BEGIN
TREEPTR_.ADDRNODE;
CMPLX1_SETCOMPLEXITY();
%(**IF THERE IS A REFERENCE TO LHS OF ASSIGNMENT STMNT SOMEWHERE IN THE
ADDRESS CALCULATION, SET FLAG IN THE ARRAYREF NODE***)%
IF .ADDRNODE[RESRFFLG] THEN CNODE[RESRFFLG]_1;
IF .ADDRNODE[FNCALLSFLG] THEN CNODE[FNCALLSFLG]_1;
END;
%1253% IF .CNODE[DBLFLG]
THEN
BEGIN
%(***CONVERT CMPLX1 FROM NUMBER OF REGS TO NUMBER OF PAIRS***)%
CMPLX1_(.CMPLX1+1)/2;
%(***FOR A DOUBLE-WD ARRAY-REF - ALWAYS NEED AT LEAST 3 REGS TO
GET THE VALUE LOADED (SINCE CANT LOAD IT INTO THE
REG USED FOR THE INDEX). HENCE NEED AT LEAST 2 PAIRS***)%
IF .CMPLX1 LSS 2 THEN CMPLX1_2;
END
%(***FOR A SINGLE-WD ARRAYREF - ALWAYS NEED AT LEAST 1 REG***)%
ELSE
IF .CMPLX1 EQL 0 THEN CMPLX1_1;
RETURN .CMPLX1
END; ! of CMPLXARRAY
GLOBAL ROUTINE CMPILF=
%(***************************************************************************
The complexity pass for an in-line-function node.
Number of regs needed is max of the following:
1. Number of regs needed to compute ARG1
2. 1+number of regs needed for computing ARG2
For MOD and CHAR, we need 1 more reg for calculating the result.
***************************************************************************)%
BEGIN
LOCAL
PEXPRNODE ARG1NODE, ! ARG1PTR from CNODE
PEXPRNODE ARG2NODE, ! ARG2PTR from CNODE
CMPLX1, ! Complexity of arg 1
CMPLX2; ! Complexity of arg 2
REGISTER
PEXPRNODE CNODE; ! Inline function node
CNODE_.TREEPTR;
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
%(***FOR CMPLX - USE CMPLA***)%
IF .CNODE[OPERSP] EQL CMPLXFN THEN
RETURN
BEGIN
IF (CMPLX1_CMPLA()) GTR 2 THEN .CMPLX1 ELSE 2
END;
%(***FOR MAX AND MIN - IF ONE OF THE ARGS IS A REAL OR NEGATIVE
CONSTANT, LET ARG1 BE THAT ARG (SINCE HAVE PROBS WITH
COMPARE-IMMED FOR REAL AN NEG CNSTS)***)%
IF .CNODE[OPERSP] EQL MAXFN OR .CNODE[OPERSP] EQL MINFN
THEN
BEGIN
IF .ARG2NODE[OPR1] EQL CONSTFL
AND .ARG1NODE[OPR1] NEQ CONSTFL
AND NOT .CNODE[A1NEGFLG]
THEN
BEGIN
IF .ARG2NODE[VALTP1] NEQ INTEG1 OR .ARG2NODE[CONST2] LSS 0
THEN
BEGIN
SWAPARGS(CNODE); !EXCHANGE THE 2 PTRS AND ALSO THE FLAGS THAT GO WITH
! THE 2 ARGS
ARG1NODE_.CNODE[ARG1PTR];
ARG2NODE_.CNODE[ARG2PTR];
END
END
END;
%(***PERFORM COMPLEXITY ANALYSIS FOR ARG1***)%
%(******************************)%
%(***PROCESS 1st ARG************)%
%(******************************)%
TREEPTR_.CNODE[ARG1PTR];
%(***IF ARG1 IS AN IMMED CNST SET A1IMMEDFLG, IF IT IS
A NON-IMMED CNST, ALLOCATE CORE FOR IT***)%
IF .ARG1NODE[OPR1] EQL CONSTFL
THEN (PRCNSTARG(.CNODE,.CNODE[ARG1PTR],TRUE);
CMPLX1_0)
ELSE
IF .CNODE[A1VALFLG]
THEN
BEGIN
%(***IF ARG IS RESULT NAME, SET RESRFFLG***)%
IF .ARG1NODE EQL .RESNAME THEN CNODE[RESRFFLG]_1;
CMPLX1_0
END
ELSE
BEGIN ! Non-zero complexity
CMPLX1_SETCOMPLEXITY();
! Set flags for "FNCALLS present under this node" and
! for ref to result under this node
IF .ARG1NODE[FNCALLSFLG] THEN CNODE[FNCALLSFLG]_1;
IF .ARG1NODE[RESRFFLG] THEN CNODE[RESRFFLG]_1;
%1567% ! If the node and arg differ in being either single or
%1567% ! double, then convert that complexity figured for the
%1567% ! argument to the mode of the parent.
%1567%
%1567% IF .CNODE[DBLFLG] AND NOT .ARG1NODE[DBLFLG]
%1567% THEN CMPLX1 = (.CMPLX1+1) ^ (-1) ! divide by 2
%1567% ELSE IF NOT .CNODE[DBLFLG] AND .ARG1NODE[DBLFLG]
%1567% THEN CMPLX1 = .CMPLX1 ^ 1; ! Mult by 2
END; ! Non-zero complexity
! For fns other than ABS if val of ARG1 can be left in a reg in
! a previous statment, bb allocator should do so. (Character
! args can't)
IF .CNODE[OPERSP] NEQ ABSFN THEN
%1567% IF .ARG1NODE[VALTYPE] NEQ CHARACTER
THEN SAVREGCONTAINING(.ARG1NODE);
%1567% ! Now that we know whether the first argument has any function
%1567% ! calls beneath it, if LEN has an array ref for an arg, we can
%1567% ! simplify the argument to be the array name and not go through
%1567% ! any calculation for the array element.
%1567% IF .CNODE[OPERSP] EQL LENFN THEN
%1567% IF .ARG1NODE[OPRCLS] EQL ARRAYREF THEN
%1567% IF NOT .ARG1NODE[FNCALLSFLG]
%1567% THEN
%1567% BEGIN
%1567% CNODE[ARG1PTR] = .ARG1NODE[ARG1PTR]; ! Array name
%1567% RETURN CMPLX1 = 1; ! Array names aren't complex
%1567% END;
%(******************************)%
%(***PROCESS 2ND ARG************)%
%(******************************)%
IF .ARG2NODE NEQ 0
THEN
BEGIN
TREEPTR_.CNODE[ARG2PTR];
%(***FOR ARG2 AN IMMED CNST, SET A2IMMEDFLG EXCEPT
IN THE CASES OF AMAX AND AMIN (SINCE CANT DO COMPARE IMMED
FOR A REAL) AND IN THE (UNLIKELY!) CASE OF SIGN***)%
IF .ARG2NODE[OPR1] EQL CONSTFL
THEN
BEGIN
IF .CNODE[OPERATOR] EQL AMAXFNOP OR .CNODE[OPERATOR] EQL AMINFNOP
OR .CNODE[OPERATOR] EQL DIMFNOP
OR .CNODE[OPERSP] EQL SIGNFN
THEN
ALOCONST(.ARG2NODE)
ELSE
IF IMMEDCNST(ARG2NODE)
THEN
BEGIN
IF .ARG2NODE[VALTP1] EQL INTEG1 AND .ARG2NODE[CONST2] LSS 0
THEN ALOCONST(.ARG2NODE)
ELSE
CNODE[A2IMMEDFLG]_1;
END
ELSE ALOCONST(.ARG2NODE);
CMPLX2_1;
END
ELSE
IF .CNODE[A2VALFLG]
THEN
BEGIN
IF .ARG2NODE EQL .RESNAME
%730% THEN CNODE[RESRFFLG]_1;
CMPLX2_1;
END
ELSE
BEGIN
CMPLX2_SETCOMPLEXITY()+1;
IF .ARG2NODE[RESRFFLG] THEN CNODE[RESRFFLG]_1;
IF .ARG2NODE[FNCALLSFLG] THEN CNODE[FNCALLSFLG]_1;
END;
END
ELSE CMPLX2_1;
%1567% ! If the node and arg differ in being either single or double,
%1567% ! then convert that complexity figured for the argument to the
%1567% ! mode of the parent.
%1567%
%1567% IF .ARG2NODE NEQ 0 THEN
%1567% IF .CNODE[DBLFLG] AND NOT .ARG2NODE[DBLFLG]
%1567% THEN CMPLX2 = (.CMPLX2+1) ^ (-1) ! divide by 2
%1567% ELSE IF NOT .CNODE[DBLFLG] AND .ARG2NODE[DBLFLG]
%1567% THEN CMPLX2 = .CMPLX2 ^ 1; ! Mult by 2
%(***IF ARG1 WILL BE COMPUTED INTO RETREG (FN RETURN REGISTER), THEN
1. IF ARG2 INCLUDES FN CALLS, THEN CANNOT COMPUTE ARG1 INTO
RETREG. UNDO THE ALLOCATION.
2. OTHERWISE, COMPUTE THE PARENT INTO RETREG ALSO
**********)%
IF NOT .CNODE[A1VALFLG] AND .ARG1NODE[ALCRETREGFLG]
THEN
BEGIN
IF NOT .CNODE[A2VALFLG] AND .ARG2NODE[FNCALLSFLG]
THEN
BEGIN
%(***UNDO THE ALLOCATION OF ARG1 TO RETREG (SINCE RETREG
WILL BE CLOBBERED WHILE COMPUTING ARG2)***)%
ARG1NODE[ALCRETREGFLG]_0;
ARG1NODE[A1SAMEFLG]_0;
ARG1NODE[A2SAMEFLG]_0;
ARG1NODE[INREGFLG]_0;
END
ELSE
BEGIN
%(***ALLOCATE CNODE TO BE COMPUTED IN RETREG***)%
CNODE[TARGTAC]_RETREG;
CNODE[INREGFLG]_1;
CNODE[A1SAMEFLG]_1;
CNODE[ALCRETREGFLG]_1;
END;
END;
IF .CMPLX2 GTR .CMPLX1 ! Return whichever complexity is greater.
THEN CMPLX1_.CMPLX2;
! Return the complexity computed. MOD and CHAR each need an
! extra register for computation.
IF .CNODE[OPERSP] EQL MODFN
THEN RETURN .CMPLX1+1
ELSE RETURN .CMPLX1;
END; ! of CMPILF
ROUTINE CMPLXSUBSTR= ![1431] New
%(**********************************************************************
**********************************************************************)%
BEGIN
REGISTER PEXPRNODE CNODE:ARGNODE;
LOCAL CMPLX1:CMPLX2:CMPLX4;
! Save pointer to substring node in CNODE
CNODE = .TREEPTR;
! Do arg 2, lower bound - 1 expression
ARGNODE = .CNODE[ARG2PTR]; ! Point to expression node
IF .CNODE[A2VALFLG]
THEN
BEGIN ! simple variable
CMPLX2 = 0; ! Complexity of a scalar is 0
IF .ARGNODE EQL .RESNAME ! Set RESRFFLG if this arg
THEN CNODE[RESRFFLG] = 1; ! matches global RESNAME
IF .ARGNODE[OPR1] EQL CONSTFL ! If it's constant, either set
THEN PRCNSTARG(.CNODE,.ARGNODE,FALSE); ! IMMEDFLG or allocate
! the constant
SAVREGCONTAINING(.ARGNODE); ! Request that it be saved if
! it's available in an AC.
END ! simple variable
ELSE
BEGIN ! expression
TREEPTR = .ARGNODE; ! Set TREEPTR to the expression
CMPLX2 = SETCOMPLEXITY(); ! Compute its complexity
IF .ARGNODE[RESRFFLG] THEN CNODE[RESRFFLG] = 1; ! Propagate
IF .ARGNODE[FNCALLSFLG] THEN CNODE[FNCALLSFLG] = 1; ! flags
END;
! Never allocate the lower bound node to RETREG (AC 0) even if it's a
! function call node since we would have to move it out of AC 0 before
! doing the ADJBP anyway. If anything is to land in AC 0, let it be
! the upper bound expression.
ARGNODE[ALCRETREGFLG] = 0;
ARGNODE[A1SAMEFLG] = 0;
ARGNODE[A2SAMEFLG] = 0;
ARGNODE[INREGFLG] = 0;
! Do arg 1, upper bound expression
ARGNODE = .CNODE[ARG1PTR]; ! Point to expression node
IF .CNODE[A1VALFLG]
THEN
BEGIN ! simple variable
CMPLX1 = 0; ! Complexity of a scalar is 0
IF .ARGNODE EQL .RESNAME ! Set RESRFFLG if this arg
THEN CNODE[RESRFFLG] = 1; ! matches global RESNAME
IF .ARGNODE[OPR1] EQL CONSTFL ! If it's constant, either set
THEN PRCNSTARG(.CNODE,.ARGNODE,TRUE); ! IMMEDFLG or allocate
! the constant
SAVREGCONTAINING(.ARGNODE); ! Request that it be saved if
! it's available in an AC.
END ! simple variable
ELSE
BEGIN ! expression
TREEPTR = .ARGNODE; ! Set TREEPTR to the expression
CMPLX1 = SETCOMPLEXITY(); ! Compute its complexity
IF .ARGNODE[RESRFFLG] THEN CNODE[RESRFFLG] = 1; ! Propagate
IF .ARGNODE[FNCALLSFLG] THEN CNODE[FNCALLSFLG] = 1; ! flags
END; ! expression
! If we have substring of an arrayref, do subscript expression
ARGNODE = .CNODE[ARG4PTR]; ! Point to base variable of
! substring, must be DATAOPR or
! ARRAYREF
IF .ARGNODE[OPRCLS] EQL DATAOPR
THEN
BEGIN ! simple variable
CMPLX4 = 0; ! Complexity of subscript is 0
IF .ARGNODE EQL .RESNAME ! Set RESRFFLG if variable
THEN CNODE[RESRFFLG] = 1; ! matches global RESNAME
IF .ARGNODE[OPR1] EQL CONSTFL ! If subscript is a constant
THEN ALOCONST(.ARGNODE); ! allocate the constant
END ! simple variable
ELSE
BEGIN ! array reference
TREEPTR = .ARGNODE; ! Point to the ARRAYREF node
SETCOMPLEXITY(); ! Compute its complexity
TREEPTR = .ARGNODE[ARG1PTR]; ! Point to base variable
IF .ARGNODE EQL .RESNAME ! Check against RESNAME
THEN CNODE[RESRFFLG] = 1;
TREEPTR = .ARGNODE[ARG2PTR]; ! Point to subscript expression
CMPLX4 = .TREEPTR[COMPLEXITY]; ! Get its complexity
IF .ARGNODE[RESRFFLG] THEN CNODE[RESRFFLG] = 1; ! Propagate
IF .ARGNODE[FNCALLSFLG] THEN CNODE[FNCALLSFLG] = 1; ! flags
END;
! Set RVRSFLG in the substring node since code generation will evaluate
! args in the order ARG2 then ARG1.
CNODE[RVRSFLG] = 1;
! The complexity of the substring node is
! max (upper, 1+lower, 1+subscript, 2)
! The various subnodes are all known to be of type integer, so their
! complexities are in registers (as opposed to register pairs).
! The complexity of the substring node is in pairs, since character
! variables have DBLFLG set. Therefore this expression must be
! rounded up and divided by 2 to convert it to pairs. Also, the
! max-of-2 term can be dropped since the rounding up takes care of it.
IF .CMPLX2 GEQ .CMPLX1 THEN CMPLX1 = .CMPLX2 + 1;
IF .CMPLX4 GEQ .CMPLX1 THEN CMPLX1 = .CMPLX4 + 1;
CMPLX1 _ (.CMPLX1+1)^(-1);
RETURN .CMPLX1;
END; ! of CMPLXSUBSTR
GLOBAL ROUTINE CMPLIOLST=
%(***************************************************************************
ROUTINE TO PERFORM THE COMPLEXITY WALK FOR AN IOLIST
CALLED WITH THE GLOBAL CSTMNT POINTING TO A STATEMENT THAT HAS
AN IOLIST ASSOCIATED WITH IT.
CALLED WITH THE GLOBALS STBSYR AND STRGCT
INDICATING WHICH REGS ARE AVAILABLE FOR USE
THE COMPLEXITY OF AN IOLIST IS EQUAL TO THE COMPLEXITY OF ITS MOST COMPLEX
ELEMENT.
***************************************************************************)%
BEGIN
MAP BASE CSTMNT;
LOCAL CMPLXMAX,CMPLX1;
LOCAL BASE IOLELEM;
LOCAL SAVSTMNT;
LOCAL SAVPAIRMODE,SAVFNREF;
%(***GET PTR TO 1ST ELEMENT ON THE IOLIST TO BE PROCESSED***)%
IOLELEM_.CSTMNT[IOLIST];
%(***SAVE PTR TO CURRENT STATEMENT (IF THERE ARE DO-STMNTS IN THE IOLIST
WILL CLOBBER CSTMNT) ***)%
SAVSTMNT_.CSTMNT;
%(***INIT THE COMPLEXITY OF THE IOLOIST TO 0****)%
CMPLXMAX_0;
%(****WALK THRU THE ELEMENTS ON THE IOLOIST*****)%
UNTIL .IOLELEM EQL 0
DO
BEGIN
IF .IOLELEM[OPRCLS] EQL STATEMENT
THEN
BEGIN
CSTMNT_.IOLELEM;
SAVPAIRMODE_.PAIRMODE; SAVFNREF_.FNREF; !(THE GLOBALS "PAIRMODE" AND "FNREF" WILL
! DESCRIBE THIS SUBSTMNT WHEN WE RETURN FROM CMSTMN - SAVE THEIR
! OLD VALUES
CMSTMN();
PAIRMODE_.SAVPAIRMODE OR .PAIRMODE; !RESTORE "PAIRMODE" - IT SHOULD
! GET SET TO "TRUE" IF THIS SUBSTMNT USED ANY PAIRS
FNREF_.SAVFNREF OR .FNREF; !RESTORE "FNREF" - IT SHOULD
! GET SET TO "TRUE" IF THIS SUBSTMNT INCLUDED ANY FN CALLS
CMPLX1_.CSTMNT[SRCCMPLX];
END
ELSE
IF .IOLELEM[OPRCLS] EQL IOLSCLS
THEN
BEGIN
CASE .IOLELEM[OPERSP] OF SET
%(***FOR A DATACALL NODE*******)%
BEGIN
TREEPTR_.IOLELEM[DCALLELEM];
%1202% IF .TREEPTR[OPR1] EQL CONSTFL THEN ALOCONST(.TREEPTR);
CMPLX1_SETCOMPLEXITY();
IF ARRNARGBLK(IOLELEM[DCALLELEM],0) THEN
CMPLX1_0;
END;
%(***FOR AN SLISTCALL NODE***)%
BEGIN
%(***PERFORM COMPLEXITY PASS FOR THE EXPRESSION TO
COMPUTE THE NUMBER OF ELEMENTS***)%
TREEPTR_.IOLELEM[SCALLCT];
%1507% IF .TREEPTR[OPR1] EQL CONSTFL
%1507% THEN ALOCONST(.TREEPTR);
%1507% ALOCONST(.ONEPLIT);
CMPLX1_SETCOMPLEXITY();
IF ARRNARGBLK(IOLELEM[SCALLCT],0) THEN
CMPLX1_0;
END;
%(***FOR AN IOLSTCALL NODE***)%
CMPLX1_CMPIOCALL(.IOLELEM);
%(***FOR AN E1LISTCALL - OPTIMIZED CODE ONLY***)%
BEGIN
LOCAL BASE SAVCSTMNT;
CMPE1LIST(.IOLELEM); !SET COMPLEXITY
SAVCSTMNT_.CSTMNT; !INCLUDE COMMON SUBS
CSTMNT_.IOLELEM; !SET STATEMENT
STCMCSB(); !INCLUDE COMMON SUBS
CMPLX1_.IOLELEM[SRCCMPLX]; !SET COMPLEXITY
CSTMNT_.SAVCSTMNT
END;
%(***FOR AN E2LISTCALL - OPTIMIZED CODE ONLY***)%
BEGIN
LOCAL BASE SAVCSTMNT;
CMPE2LIST(.IOLELEM); !SET COMPLEXITY
SAVCSTMNT_.CSTMNT; !INCLUDE COMMON SUBS
CSTMNT_.IOLELEM; !SET STATEMENT
STCMCSB(); !INCLUDE COMMON SUBS
CMPLX1_.IOLELEM[SRCCMPLX]; !SET COMPLEXITY
CSTMNT_.SAVCSTMNT
END
TES;
%(***IF THIS ELEMENT OF THE LIST REQUIRES MORE REGS TO
COMPUTE THAN ANY EARLIER ELEMENTS, SET CMPLXMAX
TO INDICATE THE NUMBER OF REGS THAT THIS ELEM NEEDS***)%
IF .CMPLXMAX LSS .CMPLX1 THEN CMPLXMAX_.CMPLX1;
END;
%(***GO ON TO NEXT ELEMENT***)%
IOLELEM_.IOLELEM[CLINK];
END;
CSTMNT_.SAVSTMNT;
CSTMNT[SRCCMPLX]_.CMPLXMAX;
END; ! of CMPLIOLST
GLOBAL ROUTINE CMPIOCALL(IOLSNODE)=
%(***************************************************************************
ROUTINE TO PERFORM THE COMPLEXITY WALK FOR AN IOLSTCALL NODE.
THE ARG IOLSNODE POINTS TO THE IOLSTCALL NODE.
THE NUMBER OF REGS THAT CAN BE USED FOR AN IOLSTCALL NODE
IS DETERMINED BY:
1. THE NUMBER OF ITEMS LEFT IN REGS ACROSS THE CALL
TO THE OPERATING SYSTEM
2. THE NUMBER OF REGS NEEDED TO COMPUTE THE EXPRESSIONS
WHICH MUST BE COMPUTED PRIOR TO CALLING THE OPERATING SYSTEM
THE COMPLEXITY OF THIS NODE IS THE MAXIMUM VALUE OF THE SUM OF:
1. THE NUMBER OF REGS NECESSARY TO COMPUTE A GIVEN EXPRESSION
2. THE NUMBER OF ITEMS PRECEEDING THIS EXPRESSION THAT WERE
LEFT IN REGS
***************************************************************************)%
BEGIN
MAP BASE IOLSNODE;
OWN SAVSTMNT;
OWN CMPLX,REGSINUSE;
OWN CMPLX1,REG1;
OWN BASE IOLELEM;
%(***SAVE PTR TO CSTMNT***)%
SAVSTMNT_.CSTMNT;
CMPLX_0;
REGSINUSE_0;
IOLELEM_.IOLSNODE[IOLSTPTR];
%(***WALK THRU THE ELEMENTS OF THE IOLST, KEEPING TRACK OF THE MAX VALUE OF
THE SUM OF THE COMPLEXITY OF A GIVEN ELEMENT WITH THE NUMBER OF REGS
BEING USED TO HOLD ELEMS BEFORE IT***)%
UNTIL .IOLELEM EQL 0
DO
BEGIN
CASE .IOLELEM[OPERSP] OF SET
%(***FOR A DATACALL NODE***)%
BEGIN
OWN PEXPRNODE DELEM; !EXPRESSION FOR DATA ELEMENT
DELEM_.IOLELEM[DCALLELEM];
TREEPTR_.DELEM;
%1202% IF .TREEPTR[OPR1] EQL CONSTFL THEN ALOCONST(.TREEPTR);
CMPLX1_SETCOMPLEXITY();
IF ARRNARGBLK(IOLELEM[DCALLELEM],0) THEN CMPLX1_0;
REG1_(IF .CMPLX1 EQL 0
THEN 0
ELSE IF .DELEM[DBLFLG] !IF THE VAL MUST BE LEFT
! IN AN EVEN-ODD PAIR
THEN 2 ! TAKE 2 REGS OUT OF SET
ELSE 1);
END;
%(***FOR A SLISTCALL NODE***)%
BEGIN
TREEPTR_.IOLELEM[SCALLCT];
%1507% IF .TREEPTR[OPR1] EQL CONSTFL
%1507% THEN ALOCONST(.TREEPTR);
%1507% ALOCONST(.ONEPLIT);
CMPLX1_SETCOMPLEXITY();
IF ARRNARGBLK(IOLELEM[SCALLCT],0) EQL 0
THEN CMPLX1_0;
REG1_0; ! Never bother to try to leave this
! count in a reg (store it in a temp
! before calling FOROTS)
END;
%(***IOLSTCALL NODE WITHIN AN IOLSTCALL NODE IS ILLEGAL***)%
CGERR();
%(***FOR AN E1LISTCALL NODE - OPTIMIZED CODE ONLY***)%
BEGIN
CMPLX1_CMPE1LIST(.IOLELEM);
REG1_0 !NO REGISTERS
END;
%(***FOR AN E2LISTCALL NODE - OPTIMIZED CODE ONLY***)%
BEGIN
CMPLX1_CMPE2LIST(.IOLELEM);
REG1_0
END
TES;
IF .REGSINUSE+.CMPLX1 GTR .CMPLX
THEN CMPLX_.REGSINUSE+.CMPLX1;
REGSINUSE_.REGSINUSE+.REG1;
IOLELEM_.IOLELEM[CLINK];
END;
IOLSNODE[SRCCMPLX]_.CMPLX;
%(***PERFORM COMPLEXITY ANALYSIS FOR COMMON SUBEXPRS UNDER THIS IOLSTCALL***)%
CSTMNT_.IOLSNODE;
STCMCSB();
%(***RESTORE CSTMNT****)%
CSTMNT_.SAVSTMNT;
RETURN .IOLSNODE[SRCCMPLX];
END; ! of CMPIOCALL
GLOBAL ROUTINE CMPE1LIST(IOLELEM)=
%(**********************************************************************
COMPUTE THE COMPLEXITY OF AN E1LISTCALL NODE
(EXCEPT FOR COMMON SUBEXPRESSIONS)
**********************************************************************)%
BEGIN
MAP BASE IOLELEM;
LOCAL BASE IOARRAY;
OWN CMPLX,REGSINUSE,CMPLX1,REG1;
%(***COMPUTE COMPLEXITY OF COUNT EXPRESSION***)%
TREEPTR_.IOLELEM[ECNTPTR]; !LOCATE EXPRESSION
%1507% IF .TREEPTR[OPR1] EQL CONSTFL
%1507% THEN ALOCONST(.TREEPTR);
CMPLX_SETCOMPLEXITY(); !INITIALIZE COMPLEXITY
IF ARRNARGBLK(IOLELEM[ECNTPTR],0)
THEN CMPLX_0; !RESET IF ARRAYREF IS REPLACED
REGSINUSE_0; !INITIALIZE REGISTER COUNT
%(***ADD IN COMPLEXITY OF INCREMENT EXPRESSION***)%
TREEPTR_.IOLELEM[E1INCR]; !LOCATE EXPRESSION
%1507% IF .TREEPTR[OPR1] EQL CONSTFL
%1507% THEN ALOCONST(.TREEPTR);
CMPLX1_SETCOMPLEXITY(); !COMPUTE COMPLEXITY
IF ARRNARGBLK(IOLELEM[E1INCR],0)
THEN CMPLX1_0; !RESET OF ARRAYREG IS REPLACED
REG1_0; !NEVER SAVE IN A REG
IF .REGSINUSE +.CMPLX1 GTR .CMPLX
THEN CMPLX_.REGSINUSE+.CMPLX1; !UPDATE COMPLEXITY
REGSINUSE_.REGSINUSE+.REG1; !UPDATE REGISTER COUNT
%(***ADD IN COMPLEXITY OF EACH ARRAYREF ON THE LIST***)%
IOARRAY_.IOLELEM[ELSTPTR]; !LOCATE LIST
WHILE .IOARRAY NEQ 0 DO
BEGIN
TREEPTR_.IOARRAY[E2ARREFPTR]; !LOCATE EXPRESSION
%1520% IF .TREEPTR[OPR1] EQL CONSTFL THEN ALOCONST(.TREEPTR);
CMPLX1_SETCOMPLEXITY(); !COMPUTE COMPLEXITY
IF ARRNARGBLK(IOARRAY[E2ARREFPTR],0) THEN CMPLX1_0;
REG1_0; !NEVER IN A REG
IF .REGSINUSE+.CMPLX1 GTR .CMPLX THEN
CMPLX_.REGSINUSE+.CMPLX1; !UPDATE COMPLEXITY
REGSINUSE_.REGSINUSE+.REG1; !UPDATE REGISTER COUNT
IOARRAY_.IOARRAY[CLINK] !NEXT ARRAYREF
END;
%(***WORK ON THE FINAL VALUE CHAIN (IF ANY)***)%
%1211% CSTMNT_.IOLELEM[ELPFVLCHAIN];
%1211% WHILE .CSTMNT NEQ 0 DO
%1211% BEGIN
%1211% CMSTMN(); ! Complexity of assignment statement
%1211% IF .CSTMNT[SRCCMPLX] GTR .CMPLX
%1211% THEN CMPLX_.CSTMNT[SRCCMPLX];
%1211% CSTMNT_.CSTMNT[CLINK] ! On to the next...
%1211% END;
%(***RETURN COMPLEXITY OF E1LISTCALL NODE***)%
RETURN (IOLELEM[SRCCMPLX]_.CMPLX)
END; ! of CMPE1LIST
GLOBAL ROUTINE CMPE2LIST(IOLELEM)=
%(**********************************************************************
COMPUTE THE COMPEXITY OF AN E2LISTCALL NODE
(EXCEPT FOR COMMON SUBEXPRESSIONS)
**********************************************************************)%
BEGIN
MAP BASE IOLELEM;
LOCAL BASE IOARRAY;
OWN CMPLX,REGSINUSE,CMPLX1,REG1;
%(***COMPUTE COMPLEXITY OF COUNT EXPRESSION***)%
TREEPTR_.IOLELEM[ECNTPTR]; !LOCATE EXPRESSION
%1507% IF .TREEPTR[OPR1] EQL CONSTFL
%1507% THEN ALOCONST(.TREEPTR);
CMPLX_SETCOMPLEXITY(); !INITIALIZE COMPLEXITY COUNTER
IF ARRNARGBLK(IOLELEM[ECNTPTR],0)
THEN CMPLX_0;
REGSINUSE_0; !INITIALIZE REGSISTER COUNTER
%(***COMPUTE COMPLEXITY OF EACH INCREMENT EXPRESSION***)%
IOARRAY_.IOLELEM[ELSTPTR]; !INITIALIZE POINTER
WHILE .IOARRAY NEQ 0 DO
BEGIN
TREEPTR_.IOARRAY[E2INCR]; !LOCATE EXPRESSION
%1507% IF .TREEPTR[OPR1] EQL CONSTFL
%1507% THEN ALOCONST(.TREEPTR);
CMPLX1_SETCOMPLEXITY(); !COMPUTE COMPLEXITY
IF ARRNARGBLK(IOARRAY[E2INCR],0) THEN CMPLX1_0;
REG1_0; !NEVER SAVE IN A REG
IF .REGSINUSE+.CMPLX1 GTR .CMPLX
THEN .CMPLX_.REGSINUSE+.CMPLX1; !UPDATE CMPLEXITY
REGSINUSE_.REGSINUSE+.REG1; !UPDATE REGISTER COUNT
IOARRAY_.IOARRAY[CLINK] !ADVANCE TO NEXT ARRAYREF
END;
%(***COMPUTE COMPLEXITY FOR ARRAYREFS***)%
IOARRAY_.IOLELEM[ELSTPTR]; !INITIALIZE POINTER
WHILE .IOARRAY NEQ 0 DO
BEGIN
TREEPTR_.IOARRAY[E2ARREFPTR]; !LOCATE EXPRESSION
%1520% IF .TREEPTR[OPR1] EQL CONSTFL THEN ALOCONST(.TREEPTR);
CMPLX1_SETCOMPLEXITY(); !COMPUTE COMPLEXITY
IF ARRNARGBLK(IOARRAY[E2ARREFPTR],0)
THEN CMPLX1_0;
REG1_0; !NEVER SAVE IN A REG
IF .REGSINUSE+.CMPLX1 GTR .CMPLX
THEN .CMPLX_.REGSINUSE+.CMPLX1; !UPDATE CMPLEXITY
REGSINUSE_.REGSINUSE+.REG1; !UPDATE REGISTER COUNT
IOARRAY_.IOARRAY[CLINK] !ADVANCE TO NEXT ARRAYREF
END;
%(***WORK ON THE FINAL VALUE CHAIN (IF ANY)***)%
%1211% CSTMNT_.IOLELEM[ELPFVLCHAIN];
%1211% WHILE .CSTMNT NEQ 0 DO
%1211% BEGIN
%1211% CMSTMN(); ! Complexity of assignment statement
%1211% IF .CSTMNT[SRCCMPLX] GTR .CMPLX
%1211% THEN CMPLX_.CSTMNT[SRCCMPLX];
%1211% CSTMNT_.CSTMNT[CLINK] ! On to the next...
%1211% END;
%(***RETURN COMPLEXITY***)%
RETURN (IOLELEM[SRCCMPLX]_.CMPLX)
END; ! of CMPE2LIST
GLOBAL ROUTINE SNGARGPROP(PARENTNODE,SON)=
%(***************************************************************************
FOR NODES THAT HAVE ONLY ONE ARGUMENT (TYPE-CONVERSION,NEGNOT,
SPECIAL OPERATORS), SET RESRFFLG,FNCALLSFLG IN THE PARENT IF
THEY ARE SET IN THE SON.
ALSO, IF THE ARG IS COMPUTED INTO
THE FN-RESULT REGISTER ("RETREG"), THEN WILL WANT TO COMPUTE
THE PARENT INTO THE SAME REGISTER (IN MOST CASES).
***************************************************************************)%
BEGIN
MAP PEXPRNODE PARENTNODE:SON;
IF .SON[ALCRETREGFLG] AND .SON[INREGFLG] AND .SON[TARGTAC] EQL RETREG
THEN
BEGIN
PARENTNODE[TARGTAC]_RETREG;
PARENTNODE[INREGFLG]_1;
PARENTNODE[ALCRETREGFLG]_1;
%(***SET FLAG IN PARENT INDICATING WHICH ARG IS IN THE SAME REG***)%
IF .PARENTNODE[ARG1PTR] EQL .SON
THEN PARENTNODE[A1SAMEFLG]_1
ELSE PARENTNODE[A2SAMEFLG]_1;
END;
IF .SON[RESRFFLG] THEN PARENTNODE[RESRFFLG]_1;
IF .SON[FNCALLSFLG] THEN PARENTNODE[FNCALLSFLG]_1;
END ; ! of SNGARGPROP
GLOBAL ROUTINE EXCHARGS(CNODE) =
%(***************************************************************************
ROUTINE TO SWAP THE 1ST AND 2ND ARGS UNDER AN EXPRESSION NODE
IF POSSIBLE
CALLED WITH THE ARG "CNODE" POINTING TO THE NODE IN QUESTION
RETURNS "TRUE" IF A SWAP WAS POSSIBLE, "FALSE" IF NOT
***************************************************************************)%
BEGIN
MAP PEXPRNODE CNODE;
%(***SHOULD ONLY CALL THIS ROUTINE FOR NODES OF OPRCLS
RELATIONAL, BOOLEAN, ARITHMETIC, OR IN LINE FN*****)%
IF .CNODE[OPRCLS] GTR ARITHMETIC THEN
BEGIN
IF .CNODE[OPRCLS] EQL INLINFN !FOR IN LINE FNS
THEN
BEGIN
IF .CNODE[OPERSP] EQL MAXFN OR .CNODE[OPERSP] EQL MINFN !FOR MAX/MIN
! CAN SWAP ARGS
THEN (SWAPARGS(CNODE); RETURN TRUE) !EXCHANGE THE PTRS AND THE FLAGS
ELSE RETURN FALSE !FOR OTHER IN LINE FNS CANNOT
END
ELSE CGERR() !IF OPERATOR IS NOT BOOLEAN,REL,ARITH OR IN LINE FN HAVE AN ERROR
END;
IF .CNODE[OPR1] EQL DIVOPF OR .CNODE[OPR1] EQL EXPONOPF
THEN
RETURN FALSE;
%(***CANNOT SWAP THE ARGS IF HAVE SUB AND THE NOT FLAG IS ON FOR
ARG2 (WHICH WOULD NOW NEED TO BE NEGATED) ***)%
IF .CNODE[OPR1] EQL MULOPF AND .CNODE[A2NOTFLG]
THEN RETURN FALSE;
%(***SWAP THE 2 POINTERS*****)%
%(****ALSO THE FLAGS CORRESPONDING TO THE 2 ARGS (IE A1NEGFLG WITH A2NEGFLG ETC) ****)%
SWAPARGS(CNODE);
%(****FOR SUBTRACTION,COMPLEMENT NEGFLG
FOR THE ARG THAT WAS MOVED FROM 2ND TO 1ST AND
CHANGE OPERSP FROM "SUB2 TO "ADD"*******)%
IF .CNODE[OPR1] EQL SUBOPF
THEN
BEGIN
CNODE[OPR1]_ADDOPF;
CNODE[A1NEGFLG]_NOT .CNODE[A1NEGFLG];
END;
%(****FOR RELATIONALS(EXCEPT EQ AND NE) REVERSE THE MODE
OF THE RELATIONAL (EG SET LT TO GT, LE TO GE, ETC)*****)%
IF .CNODE[OPRCLS] EQL RELATIONAL
THEN
BEGIN
IF NOT EQREL(.CNODE[OPERSP])
THEN
CNODE[OPERSP]_REVREL(.CNODE[OPERSP]);
END;
RETURN TRUE;
END; ! of EXCHARGS
END
ELUDOM