!THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED ! OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. !COPYRIGHT (C) 1972,1977 BY DIGITAL EQUIPMENT CORPORATION !AUTHOR: NORMA ABEL/HPW/DCE/SJW MODULE COMSUB(RESERVE(0,1,2,3),SREG=#17,VREG=#15,FREG=#16,DREGS=4,GLOROUTINES)= BEGIN ! REQUIRES FIRST, TABLES, OPTMAC GLOBAL BIND COMSV = 5^24 + 1^18 + 265; !VERSION DATE: 22-SEP-77 %( REVISION HISTORY 198 ----- ----- ADD INTERFACE TO I/O LIST OPTIMIZER 199 ----- ----- FIX MOVCNST TO SUBSUME 200 ----- ----- EXTEND XPUNGE TO COMPUTE PLACE FOR EXPRESSIONS ON AN I/O LIST 201 ----- ----- CORRECTED TYPOS FROM 199 202 ----- ----- REMOVED BAD DOT IN DOTOHASGN 203 ----- ----- REMOVED BAD COMPARE FROM UNRYMATCH MAKE PHI A PARAMETER TO CMNMAK 204 ----- ----- FIX MOVCNST TO DELETE HASH ENTRIES MOVE EHASHP TO BEGINNING OF MODULE 205 ----- ----- INTERFACE TO IOGELM TO WALK I/O LISTS AND DO GLOBAL SUBEXPRESSION ELIMINATION 206 ----- ----- MAKE DOTOHASGN AWARE OF I/O LISTS MAKE GLOBELIM AWARE OF I/O LISTS 207 ----- ----- WRONG PARAMETER IN CALL TO DOTOHASGN IN MATCHER 208 ----- ----- REARRANGE INTERACTION OF GLOBLDEPD,CHKHAIR AND MOVCNST 209 ----- ----- FIX SLINGHASH 210 ----- ----- FIX MOVCNST INPROVEMENT MADE IN 208 211 ----- ----- MORE TO COMPLETE 208 CORRECTLY 212 ----- ----- ADD AN ITERATION BETWEEN MOVCNST AND GLOBDEPD 213 ----- ----- ANOTHER FIX TO EDIT 208 214 ----- ----- ANOTHER ONE 216 ----- ----- REDEFINE CNSMOVFLG TO BE A BIT IN IMPLDO 217 ----- ----- FIX CHKDOMINANCE TO WORK CORRECTLY WITH CNSMOVFLG 215 ----- ----- AGAIN 218 ----- ----- MAKE THE ROUTINES FOR GLOBAL CMN ONLY INTO A SEPARATE MODULE 219 ----- ----- ADD THE VARIABLE OR EXPRESSION TO BE LINKED TO THE LIST OF PARAMETERS FOR CMNLNK 220 ----- ----- FIX CALL TO DOTOHASGN SO IT IS ONLY CALLED ONCE 221 ----- ----- DONT USE IDADDR FIELD SO DATA OPTS CAN BE DONE 222 ----- ----- MAKE NEXTUP LOOK AT SKEWED TREES FOR ARITHMETICS 223 ----- ----- CALL IOGELM FOR READ/WRITE/ENCODE/DECODE 224 ----- ----- ADD REREDID TO IOGELM 225 ----- ----- FIX ELIM TO TEST GCALLSLFLG 226 ----- ----- REEXAMINE DEFPTS IF OPTIMIZING IN HASHIT 227 ----- ----- ADD ARRAY REFERENCE PROCESSING 228 ----- ----- FIX TYPOS IN 227 229 ----- ----- MORE OF 228 230 ----- ----- CORRECT NEWCOPY TO RETURN POINTER TO NODE BUILT 231 ----- ----- ADD ROUTINE SCRUBARRAY AND MAKE CMNMAK GLOBAL 232 ----- ----- PUT ARRAY STUFF UNDER OPTIMIZER SWITCH. DELETE ARRAY SPECIFIEC ROUTINES. 233 ---- ----- FIX ARRAY HASH KEY TO INCLUDE OFFSET 234 ----- ----- ADD ARRAYREF FUNCTION STUFF AND FIX NARY2 TO PUT ARRAY STUFF BACK INTO NODES 235 ----- ----- MAKE CHKHAIR AND MAKETR AWARE OF TREE SHAPE 236 ----- ----- CMNMAK IS BLOWING ARRAY REPLACEMENT 237 ----- ----- MAKE NEXTUP LOOK UP AS WELL AS DOWN FOR SKEWED EXPRESSIONS 238 ----- ----- MAKE MAKETRY TAKE BLKID FROM ENTRY OS ARRAYS WILL MATCH 239 ----- ----- IN MATCHER BUILD NARY EXPRESSION WITH ARG1 AND ARG2 IN THE RIGHT PLACE 240 ----- ----- FIX MATCHER TO DEAL CORECTLY WITH NEXTUP NARY2 INTERFACE 241 ----- ----- SET NOHHASSLE BIT IN CMNMAK 242 ----- ----- FIX RANDOM P IN DELETE (V1 BUG TOO) 243 ----- ----- FIX LINKING OUT OF NODE TO BE DELETED IN ROUTINE DELETE 244 ----- ----- FIX HASHIT SO THAT A+B==-(A+B) IS FOUND AS A COMMON SUB 245 ----- ----- LIKE ARRAYREF NODES TOGETHER WHEN MATCHED AND RETRIEVE FROM LINKED LIST WHEN NEEDED. PARENT FIELD IS LINK 246 ----- ----- IN UNRYMATCHER IN LOCL CASE WE WILL MISS (MESS) BECAUSE T GET S CONFUSED 247 ----- ----- FIX NEGNOT FLAG BUG WITH SPECOPS 248 ----- ----- FIX MORE NEGNOT PROBLEMS WITH TYPCONV AND NEGNOTS 249 ----- ----- NEGNOTS ON SKEWED TREES MESSED UP 250 ----- ----- PUNT! 251 ----- ----- CMNMAK SHOULD CALL PUTBACKARRAY TO PUT THE ARRAREF BACK. ALL THE RIGHT LOGIC IS THERE. 252 ----- ----- THE RIGHT LOGIC MAY THERE IN EDIT 251 BUT ITS FOR THE WRONG (POTENTIALLY) EXPRESSION. 253 ----- ----- LOK1SUBS CASE STATEMENT IS MISSING ARRAYREF 254 ----- ----- UNARY MATCHER IS CALLING NEXTUP IMPROPERLY FOR A LOCAL SPECIAL CASE 255 371 18471 FIX CSE FOR STRAIGHT NON-SKEWED CASE 256V VER5 ----- X OP .R -> .R OP X FIND CSE'S CONTAINING ARRAYREFS IF OPTIMIZING RETURN OMOVDCNS FOR LOK1/2SUBS TO GLOBDEPD DON'T ELIM I/O STATEMENTS ON 2ND GLOBELIM 256 405 18967 FIX IOLISTS WITH STAR1 AND STAR2 SHAPES 257 427 18771 FIX IOLISTS WITH COMMON SUBS WHICH ARE SHAPES GREATER THAN SKEW 258 442 19233 FIX DELETE SO IT DOESN'T LOSE SOME HASH ELEMENTS OTHER THAN ONE BEING DELETED 259 450 QA784 DON'T NEXTUP AN ARRAYREF INSIDE AN IOLIST 260 456 QA784 PASS ENTIRE HASH ENTRY TO GLOBMOV IN CMNMAK FOR FINDPA FOR FINDTHESPOT BEGIN VERSION 5A, 7-NOV-76 261 520 21271 RELATIONAL COMMON SUBS CANNOT HAVE NEG FLAGS SET 262 524 QA876 PUT BACK ARRAY REF IN STPRECLUDE AFTER A MATCH SO CAN NEXTUP THE EXPR CONTAINING THE ARRAY REF AND NOT RUN INTO A HASH TABLE ENTRY CALL STPRECLUDE BEFORE CMNMAK CHANGES NEG FLAGS IN MATCHER 263 566 22701 SKEWED COMSUBS INVOLVING NOTFLAGS ARE NOT HASHED UNIQUELY - USE THE CORRECT FLAGS! 264 602 22700 FIX SKEWED EXPRESSIONS IN IOLISTS WITH CORRECT DEFINITION POINT CALCULATION 265 620 23720 D.P. ARRAY REF IN IO LIST CAUSES PROBLEMS )% SWITCHES NOLIST; REQUIRE FIRST.BLI; REQUIRE TABLES.BLI; REQUIRE OPTMAC.BLI; SWITCHES LIST; SWITCHES NOSPEC; !*************************************************************** ! COMMON SUB EXPRESSION ELIMINATION MODULE. ! LOCAL AND GLOBAL BOTH INCLUDED TOGETHER WITH ! MOTION OF CONSTANT EXPRESSIONS OUT OF LOOPS IN THE GLOBAL CASE ! THE LOCAL CONTROL ROUTINE IS LOCELIM. ! THE GLOBAL CONTROL ROUTINE IS GLOBELIM. !****************************************************************** ! NOTE: ! THERE ARE TWO WAYS USED TO DISTINGUISH BETWEEN THE ! LOCAL AND GLOBAL CASES. ! 1. BACKST=0; GLOBAL CASE ! BACKST#0; LOCAL CASE ! 2. FLGRG=1; GLOBAL CASE ! FLGRG=0; LOCAL CASE ! TESTS ON THESE ARE MADE INTERCHANGABLY. THE ! TWO WAYS ARE PRESENT FOR HISTORIC REASONS. EXTERNAL CORMAN,LENTRY,QQ,TOP,BOTTOM,TPREV; MAP PEXPRNODE LENTRY; EXTERNAL GETOPTEMP; FORWARD TBLSRCH,DELETE,MAKETRY,XPUNGE; EXTERNAL PHI; OWN P,PAE,PB,PA,PC,PO,T; EXTERNAL EHASHP; EXTERNAL LOCLNK; OWN P1,P2; MAP PEXPRNODE P1:P2; MAP PEXPRNODE P:PHI:PAE:PA:PB:PC:QQ:PO; EXTERNAL MAKEPR; MAP PHAZ2 TPREV; EXTERNAL GLOBMOV,GLOBDEPD,CHKINIT,DOTOHASGN; FORWARD HASHIT,LOCLMOV,LOCLDEPD; OWN STHASCMN; !USED BY LOCAL COMMONSUB EXPRESSIONS TO !TO SAVE A SCAN OF EHASH IF THE STATEMENT !WAS NOT EVEN ONE THAT POTENTAILLY HAD A !COMMON SUB-EXPRESSION (LIKE END). EXTERNAL NAN; OWN TS, !TEMP USED THROUGH OUT VARHOLDER, !USED IN SPECIAL LOCAL CASES SEE UNRYMATCHER NEDCOR; !FLAG SET BY TBLSRCH TO INDICATE IF THE !HASH TABLE HAS A FREE REUSABLE SPACE OR !CORE IS NEEDED FOR THE ENTRY. 1=LATTER. EXTERNAL ARGCONE; EXTERNAL NEWCOPY,A2ARREF,A1ARREF; GLOBAL ROUTINE CMNMAK(PAE,NAN,PHI)= BEGIN !CREATE A COMMON SUB-EXPRESSION NODE POINTING TO !THE EXPRESSION !A COMMON SUB-EXPRESSION NODE HAS ! OPRCLS - CMNSUB ! OPERSP - NULL ! A SINGLE ARGUMENT (ARG2PTR) POINTING TO ! THE EXPRESSION (OR SINGLE VARIABLE) MAP PEXPRNODE PAE; MAP PHAZ2 PHI; EXTERNAL PUTBACKARRAY; !THIS ROUTINE IS CALLED IN BOTH THE GLOBAL AND LOCAL CASES !THIS IS THE POINT AT WHICH THEY DIVERGE. !A POINTER TO A CMNSUB *EXPRESSION NODE* IS RETURNED IN THE LOCAL !CASE. A POINTER TO A TEMP IN THE GLOBAL CASE. !IN BOTH CASES PHI[TEMPER] IS SET CORRECTLY AND RETURNED. !IF DOING AN ARRAY REFERENCE PICK UP THE TO THE HASH TABEL !AND THE ARRAYREFERENCE ITSELF. THIS ADJUSTMENT IS MADE TO !THE EXPRESSION BEFORE ANY OTHER PROCESSING HERE. !IF THE FLAG NAN (NEEDS A NEGATE) IS SET, COMPLEMENT/RESET !THE NEGFLAGS IN THE EXPRESSION BEFORE IT BECOMES THE !COMMON SUBEXPRSSSION. IF .NAN THEN BEGIN !FOR AN ADD COMPLEMENT THE FLAGS IF .PAE[OPR1] EQL ADDOPF THEN BEGIN PAE[A1NEGFLG]_NOT .PAE[A1NEGFLG]; PAE[A2NEGFLG]_NOT .PAE[A2NEGFLG]; END ELSE IF (.PAE[OPRCLS] EQL ARITHMETIC) OR (.PAE[OPRCLS] EQL SPECOP) OR (.PAE[OPRCLS] EQL TYPECNV) OR (.PAE[OPRCLS] EQL NEGNOT) THEN !MULTIPLE, DIVIDE,EXPONENTIATE BEGIN PAE[A1NEGFLG]_0; PAE[A2NEGFLG]_0; END; END; IF NOT .FLGREG THEN BEGIN NAME_4; P_CORMAN(); P[OPRCLS]_CMNSUB; P[ARG2PTR]_.PAE; IF .PAE[VALTYPE] NEQ CONTROL THEN P[VALTYPE]_.PAE[VALTYPE] ELSE P[VALTYPE]_LOGICAL; IF .PAE[OPRCLS] EQL DATAOPR THEN P[A2VALFLG]_1; PHI[TEMPER]_.P; !CALL ROUTINE THAT WILL ADD EXPRESSION TO LINKED LIST LOCLMOV(.P); END ELSE !GLOBAL CASE BEGIN IF .ARREFCMNSBFLG THEN BEGIN NOHHASSLE_1; !TAKE CARE OF POTENTIAL ARRAY REFERENCES !WE KNOW THE SHAPE IF THE FIRST EXPRESSION BUT !THIS DOES NOT RELATE (NECESSARILY) TO PAE !SO WE WILL EXPLICITLY EXAMINE PAE TO PUT THE !ARAYREF BACK. IF (P_.PAE[ARG1PTR]) NEQ 0 THEN !IS IT THE ARRAYREF HASH ENTRY !COINCIDENCE BETWEEN HOP AND OPRCLS MAKES !THIS TEST POSSIBLE IF .P[OPRCLS] EQL ARRAYREF THEN PAE[ARG1PTR]_NEWCOPY(.P,.PAE); !IT COULD ALSO BE THAT PAE IS A FUNCTION REF IF .PAE[OPRCLS] EQL FNCALL THEN PUTBACKARRAY(.PHI,STGHT) ELSE BEGIN IF (P_.PAE[ARG2PTR]) NEQ 0 THEN IF .P[OPRCLS] EQL ARRAYREF THEN PAE[ARG2PTR]_NEWCOPY(.P,.PAE); END; END; P_PHI[TEMPER]_GETOPTEMP(IF .PAE[VALTYPE] EQL CONTROL THEN LOGICAL ELSE .PAE[VALTYPE]); P[IDOPTIM]_.PAE; !CALL ROUTINE THAT CREATS AND LINKS IN ASSIGNMENT STATEMENT !**[456] CMNMAK @3780 SJW 22-SEP-76 ![456] PASS GLOBMOV ENTIRE HASH ENTRY SO CAN DO FINDPA FOR FINDTHESPOT %[456]% GLOBMOV (.PAE, .PHI, .P); END; .PHI[TEMPER] END; EXTERNAL FINDTHESPOT; ROUTINE STPRECLUDE(CNODE)= BEGIN !PART OF THE COUNT HASSLE. !IF A COMMON - SUB EXPRESSION HAS JUST BEEN FOUND !THAT IS PART OF AN NARY STRUCTURE IT MAY HAVE TO BE DELETED. !FOR THE GLOABL CASE IT MUST BE DELETED TO PREVENT IT FROM !APPEARING TO BE A CONSTANT COMPUTATION. IN THE LOCAL CASE !IT MAY OCCUR WHEN AN NARY ENTRY HAS BEEN MADE WHILE WALKING ONE !TREE AND IT IS DISCOVERED THAT (WHILE WALKING ANOTHER TREE) !THE WHOLE THING COLLAPSES UPWARD AS A COMMON-SUB. EXTERNAL SKERR; MAP BASE QQ:TS:CNODE; QQ_.CNODE[PARENT]; !CHECK FOR ERROR IF .QQ EQL 0 THEN SKERR(); !SEE IF IT NARY !**[524] STPRECLUDE @3815 SJW 2-DEC-76 %[524]% IF .QQ [OPR1] NEQ .CNODE [OPR1] %[524]% THEN RETURN; %[524]% IF .QQ [A2VALFLG] %[524]% THEN BEGIN !NOW ITS NARY CHECK FOR B OP B OP B IF (.CNODE[ARG1PTR] EQL .CNODE[ARG2PTR]) AND (.CNODE[ARG2PTR] EQL .QQ[ARG2PTR]) THEN !GET THE #$$$() OUT RETURN; HASHIT(.QQ,SKEW); TS_TBLSRCH(); !IF ITS THIS ONE (JUDGING BY SHAPE AND NOT !A COMMON SUB IN ITS OWN RIGHT ALREADY FOR OTHER !REASONS THEN DELETE IT IF .FLAG THEN IF .TS[TEMPER] EQL 0 AND .TS[NBRCH] THEN DELETE(.TS,1); END; !**[524] STPRECLUDE @3830 SJW 2-DEC-76 ![524] IF /OPT, MUST CHECK IF EXPR IS A OP B OP ARRAYREF. IF IT IS, ![524] MUST DROP USECNT OF HASH ENTRY FOR ARRAYREF BY 1 SO MAYBE THE ![524] ARRAYREF WILL BE PUT BACK IN PLACE OF THE HASH TABLE ENTRY %[524]% IF NOT .FLGREG %[524]% THEN RETURN; %[524]% HASHIT (.QQ, SKEW); %[524]% TS _ TBLSRCH (); %[524]% IF .FLAG THEN IF %[524]% .TS [TEMPER] EQL 0 THEN IF %[524]% .TS [NBRCH] %[524]% THEN DELETE (.TS, 1); END; ROUTINE NARY2(CNODE)= !ROUTINE CALLED FROM MATCHER WHEN A MATCH ON A SKEWED !TREE HAS BEEN MADE. A SKEWED NODE IS OP A OP B. WE !NEED TO DELETE FROM THE HASH TABLE USED OF !ANYTHING OP A AND B OP ANYTHING, AT THE SAME TIME !BEING CAREUL NOT TO *MESS-UP* B OP B OP B OP B OP B. BEGIN OWN BSAMEFLG; MAP BASE TS; MAP PEXPRNODE CNODE; ROUTINE BOPBOPB(SHAPE)= BEGIN !LOCAL ROUTINE TO SAVE SOME CODE SPACE !HASHES EXPRESSION OF SHAPE SHAPE, LOOKS !IT UP IN THE TABLE AND DELETES IT USE COUNT BY 1 !SET UP HASH KEY HASHIT(.QQ,.SHAPE); !DO TABLE LOOKUP TS_TBLSRCH(); !IF ENTRY WAS IN THE TABLE AND IT MATCHES !IN SHAPE WITH THE ONE NOW CONSIDERED, THEN !DECREASE ITS USE COUNT BY 1. SEE DOCUMENTATION !FOR A DETAILED DESCRIPTION OF WHY, WHO, HOW. IF .FLAG THEN IF .TS[TEMPER] EQL 0 THEN IF (.SHAPE EQL SKEW AND .TS[NBRCH]) OR (.SHAPE EQL STGHT AND NOT .TS[NBRCH]) THEN DELETE(.TS,1); END; QQ_.CNODE[ARG1PTR]; !FIRST DECIDE IF THIS IS A OP A. IT IS A PROPBLEM, IF IT IS BSAMEFLG_0; IF .QQ[ARG2PTR] EQL .CNODE[ARG2PTR] THEN BSAMEFLG_1; IF .QQ[A1VALFLG] AND .QQ[A2VALFLG] THEN BEGIN IF .BSAMEFLG AND .QQ[ARG1PTR] EQL .CNODE[ARG2PTR] THEN !WE HAVE B OP B OP B ELSE BOPBOPB(STGHT); END ELSE BEGIN !LOOK DOWN ONE MORE QQ_.QQ[ARG1PTR]; IF .BSAMEFLG AND .QQ[ARG2PTR] EQL .CNODE[ARG2PTR] THEN !WE HAVE B OP B OP B ELSE BEGIN !FOR THE HASH, WHICH DEPENDS ON QQ !IN THIS CASE, MOVE QQ BACK UP QQ_.CNODE[ARG1PTR]; !LOOKING DOWN MAY CAUSE AN ARRAY HASH ENTRY !TO APPEAR IF OPTIMIZING. WE WILL HAVE TO !SPECIAL CASE IT HERE IF .FLGREG THEN BEGIN HASHIT(.QQ,STGHT); !TRY HASHING IT STRAIGHT AND SEE IF IT !IS THERE WITH THE ARRAY BITS SET TS_TBLSRCH(); IF .FLAG THEN BEGIN IF .TS[A1ARY] OR .TS[A2ARY] THEN DELETE(.TS,1); END; END; BOPBOPB(SKEW); END; END; QQ_.CNODE[PARENT]; IF .QQ[OPR1] EQL .CNODE[OPR1] THEN BEGIN IF .BSAMEFLG AND .QQ[ARG2PTR] EQL .CNODE[ARG2PTR] THEN !ONCE AGAIN B OP B OP B ELSE BOPBOPB(SKEW); END; END; ! !******************************************** ! %********************************* MACROS TO CHECK PROPER VALFLAGS AND CALL REA FOR THE NEXT LEVEL UP OF AN EXPRESSION THAT HAS JUST BEEN MATCHED. ************************************% MACRO ARGSBOTH(NOD)= IF .NOD[A1VALFLG] AND .NOD[A2VALFLG] THEN XPUNGE(.NOD,STGHT)$; MACRO ARGS1(NOD)= IF .NOD[A1VALFLG] THEN XPUNGE(.NOD,UNARY)$; MACRO ARGS2(NOD)= IF .NOD[A2VALFLG] THEN XPUNGE(.NOD,UNARY)$; FORWARD CHKHAIR,REA,CMNLNK; ROUTINE NEXTUP(EXPR)= BEGIN !CASE STATEMENT CONTROL ON LOOKING AT THE NEXT EXPRESSION !UP AFTER A MATCH. MAP BASE EXPR; EXTERNAL BASE QQ; %[V5]% EXTERNAL A1ARREF, A2ARREF; IF .EXPR EQL 0 THEN RETURN; CASE .EXPR[OPRCLS] OF SET ARGSBOTH(EXPR); !BOOLEAN RETURN; !DATAOPR - ILLEGAL !RELATIONALS ARE SPECIAL. AT THIS POINT !WE ARE ONLY INTERESTED IN THE RELATIONAL ITSELF !AND NOT THE LOCAL SPECIAL SINGLE VARIABLE CASE AT ALL !REA WOULD INCLUDE THIS SPECAIL CASE. !WE WILL CALL XPUNGE DIRECTLY TO PREVENT THIS IF .EXPR[A1VALFLG] AND .EXPR[A2VALFLG] THEN XPUNGE(.EXPR,STGHT); !FNCALL IF ARGCONE(.EXPR) THEN XPUNGE(.EXPR,UNARY); BEGIN !ARITHMETIC !GET THE OBVIOUS STRAIGHT CASE ARGSBOTH(EXPR) %[V5]% ELSE BEGIN ! CHECK ARRAY REFS %[V5]% QQ _ .EXPR [ARG1PTR]; %[V5]% IF .FLGREG AND .QQ [OPRCLS] EQL ARRAYREF %[V5]% THEN A1ARREF (.EXPR) %[V5]% ELSE BEGIN %[V5]% QQ _ .EXPR [ARG2PTR]; %[V5]% IF .FLGREG AND .QQ [OPRCLS] EQL ARRAYREF %[V5]% THEN A2ARREF (.EXPR) ELSE BEGIN !TRY FOR SKEWED TREES TOO QQ_.EXPR[ARG1PTR]; !CHECK SKEW PROPERTIES IF (.QQ[OPR1] EQL .EXPR[OPR1]) AND (.QQ[OPR1] NEQ DIVOPF) AND (NOT .QQ[PARENFLG]) AND .QQ[A2VALFLG] THEN XPUNGE(.EXPR,SKEW); !LOOK UP IF (QQ_.EXPR[PARENT]) NEQ 0 THEN BEGIN IF (.QQ[OPR1] EQL .EXPR[OPR1]) AND (.QQ[OPR1] NEQ DIVOPF) AND (NOT .EXPR[PARENFLG]) AND .QQ[A2VALFLG] AND .EXPR[A2VALFLG] THEN XPUNGE(.QQ,SKEW); END; %[V5]% END; END; END; END; ARGS2(EXPR); !TYPECNV %[V5]% BEGIN !ARRAYREF %[V5]% LOCAL BASE MOM; %[V5]% %[V5]% IF NOT .FLGREG %[V5]% THEN RETURN; %[V5]% MOM _ .EXPR [PARENT]; %[V5]% IF .MOM [OPRCLS] EQL STATEMENT %[V5]% THEN RETURN; !**[450] NEXTUP @4009 SJW 17-SEP-76 ![450] CAN'T NEXTUP ARRAYREF IF INSIDE IOLIST %[450]% IF .MOM [OPRCLS] EQL IOLSCLS %[450]% THEN RETURN; %[V5]% ! FIND TREE SHAPE & CALL XPUNGE %[V5]% IF .MOM [ARG1PTR] EQL .EXPR %[V5]% THEN A1ARREF (.MOM) %[V5]% ELSE A2ARREF (.MOM); %[V5]% END; RETURN; !CMNSUB - ILLEGAL ARGS2(EXPR); !NEGNOT ARGS1(EXPR); !SPECOP RETURN; !FIELDREF RETURN; !STORECLS RETURN; !REGCONTENTS RETURN; !LABOP RETURN; !STATEMENT RETURN; !IOLSCLS BEGIN !INLINFN IF .EXPR[ARG2PTR] NEQ 0 THEN BEGIN ARGSBOTH(EXPR) END ELSE ARGS1(EXPR); END TES; END; EXTERNAL REPLACARG; ROUTINE UNRYMATCH(CNODE,NAN,PHI)= BEGIN !FIXES UP (PERFORMS MATCHER FUNCTIONS ) FOR A UNARY SHAPE !(TYPECNV,ARRAYREF SPECIAL CASE, LIBRARY FUNCTION). !PHI IS POINTER TO HASHED ENTRY (INDEX). !NAN SHOULD BE SET ONLY ON NOT NODES, TYPECNV NODES OR FUNCTION CALLS MAP PEXPRNODE CNODE:PHI; !GET OUT IF ITS AN ARRAYREF IF .CNODE[OPRCLS] EQL ARRAYREF THEN BEGIN !BETTER ONLY BE HERE WHEN GLOBALLY OPTIMIZING IF .FLGREG THEN BEGIN !MAKE LINKED LIST OFF OF LKER FIELD OF PHI !USING PARENT POINTERS OF ARRAYREF NODES CNODE[PARENT]_.PHI[LKER]; PHI[LKER]_.CNODE; END; RETURN; END; !IN THE GLOBAL CASE CHECK THE FIRST ENTRY TO SEE IF IT IS !AN ASSIGNMENT TO A OPTIMIZER .O TEMP. IF .FLGREG THEN IF .CNODE[OPRCLS] NEQ DATAOPR AND .PHI[USECNT] EQL 1 THEN BEGIN DOTOHASGN(.PHI[LKER],.PHI); !IF SUBSUMPTION HAPPENED THEN !DO ONLY THE SECOND HALF A QUIT IF .PHI[TEMPER] NEQ 0 THEN BEGIN PHI[USECNT]_.PHI[USECNT]+1; CMNLNK(.PHI[TEMPER],.CNODE,UNARY,.NAN,.PHI); RETURN; END; END; IF .PHI[USECNT] EQL 1 THEN BEGIN PHI[USECNT]_2; !MAKE CMNSUB NODE AND FIX UP OLD ENTRY !WE MUST SET PC BEFORE THE CALL TO CMNMAK !IN ORDER TO CORRECTLY HANDLE THE SPECIAL LOCAL !COMMON SUB-EXPRESSION CASE OF A SINGLE VARIABLE !SUBSCRIPT OR UNDER A RELATIONAL. IN THIS !CASE PHI[TEMPER] HOLDS THE POINTER TO THE !EXPRESSION FOR RELINKING. CMNMAK WILL CHANGE !PHI[TEMPER] IF .CNODE[OPRCLS] EQL DATAOPR THEN PC_.PHI[TEMPER] ELSE PC_.PHI[LKER]; !FIRST RESET ANY NEG FLAGS ON THE NODE WE ARE !ABOUT TO MAKE A COMMON SUB-EXPRESSION !QQ IS USED AS A TEMP QQ_.PHI[LKER]; IF .QQ[OPRCLS] NEQ DATAOPR THEN BEGIN QQ[A1NEGFLG]_0; QQ[A2NEGFLG]_0; END; T_CMNMAK(.PHI[LKER],0,.PHI); QQ_CMNLNK(.T,.PC,UNARY,.PHI[NEDSANEG],.PHI); !QQ CONTAINS THE PARENT POINTER ON RETURN. !BUT BE CAREFUL**********. !CHECK FOR THE SPECIAL LOCAL CASE OF !RELATIONAL OR ARRAYREF, CUZ QQ WILL POINT TO !THE RELATIONAL OR ARRAYREF. IF .CNODE[OPRCLS] EQL DATAOPR THEN ELSE NEXTUP(.QQ); END ELSE PHI[USECNT]_.PHI[USECNT]+1; T_.PHI[TEMPER]; !NOW FIX UP CURRENT REFERENCE (IN ALL CASES) !NOTE THE SPECIAL TEST FOR THE SAME REASON AS DESCRIBED ABOVE !. VARHOLDER IS THE MODULE OWN THAT POINTS TO THE EXPRESSION !IN THIS CASE CMNLNK(.T,IF .CNODE[OPRCLS] EQL DATAOPR THEN .VARHOLDER ELSE .CNODE,UNARY,.NAN,.PHI); END; ROUTINE CHK4OPS(CNODE)= BEGIN !IF WE HAVE A OP A OP A OP A !WHEN WE ARE MATCHING A OP A WITH A OP A WE !WOULD UNLESS OTHERWISE PREVENTED ENTER INTO THE !HASH TABLE CMN(A OP A) OP A. IF THERE IS ANOTHER !A OP A OP A OP A IN THE WORLD THIS WILL !LEAD TO A FALSE MATCH AND INCORRECT CODE. !THE PURPOSE OF THIS ROUTINE IS TO PREVENT THAT !TROUBLE MAKING ENTRY. 0 IS RETURNED IF THE ENTRY IS OK !1 IF NOT. MAP PEXPRNODE CNODE:TS; IF NOT .CNODE[A1VALFLG] THEN BEGIN !THE TREE MUST BE SKEWED. TS_.CNODE[ARG1PTR]; !CHECK FOR A OP A IF .TS[ARG2PTR] EQL .CNODE[ARG2PTR] THEN BEGIN !IF ARG1 IS THE NODE WERE SUBSTITUTING THEN !THIS IS THE BAD CASE. IF .TS[ARG1PTR] EQL .T THEN RETURN(1); END; END; END; ROUTINE MATCHER(CNODE,SHAPE,NAN,PHI)= !CALLED ON A HIT IN THE HASH TABLE. !PHI POINTS TO THE MATCHING ENTRY. !CNODE IS EXPRESSION NODE. !SHAPE IS UNARY,STGHT(STRAIGHT), OR SKEW(SKEWED) OF CURRENT EXPRESSION !SEE ROUTINE HASHIT FOR PICRURES OF THE TREE SHAPES !NAN IS NEEDS A NEGATIVE(NEGATION) BEGIN EXTERNAL OLDHEAD; MAP PHAZ2 CNODE:PHI:T; !GO TO SPECIAL ROUTINE IF SHAPE IS UNARY IF .SHAPE EQL UNARY THEN BEGIN UNRYMATCH(.CNODE,.NAN,.PHI); RETURN; END; !CHECK FOR ASSIGNMENT TO .O VARIABLE IF .FLGREG THEN IF (.SHAPE EQL STGHT) AND (.PHI[USECNT] EQL 1) AND NOT .PHI[NBRCH] THEN DOTOHASGN(.PHI[LKER],.PHI); IF .PHI[USECNT] EQL 1 AND .PHI[TEMPER] EQL 0 THEN BEGIN PHI[USECNT]_2; IF .SHAPE EQL SKEW THEN !SKEWED TREE BEGIN !ALSO CATCH B*B*B*B, TEST AFTER NARY2 WILL !STOP ALL COMMON SUBS OR MERELY CORRECT THE !SITUATION FOR B*B*B, HOPEFULLY, THIS WILL !PERMIT B*B*B*B TO BECOME (T=B*B,T*T). IF .CNODE[ARG1PTR] EQL .PHI[LKER] THEN BEGIN PHI[USECNT]_1; !GET OUT RETURN; END; NARY2(.CNODE); !PRECLUDE TRIPLES ELIMINATED BY MATCH IF .PHI[NBRCH] THEN !ENTRY IN HASH TABLE IS ALSO SKEWED BEGIN QQ_.CNODE[ARG1PTR]; PB_MAKEPR(.CNODE[OPRCLS], !MAKE A STRAIGHT ONE .CNODE[OPERSP], .CNODE[VALTYPE], .QQ[ARG2PTR], .CNODE[ARG2PTR]); PB[DEFPT1]_.QQ[DEFPT2]; PB[DEFPT2]_.CNODE[DEFPT2]; PB[A1FLGS]_.QQ[A2FLGS]; PB[A2FLGS]_.CNODE[A2FLGS]; NARY2(.PHI[LKER]); !ELIMINATE TRIPLES PRECLUDED BY MATCH T_CMNMAK(.PB,.NAN,.PHI); !MAKE A CMN SUB PC_.PHI[LKER]; PB[PARENT]_.PC[PARENT]; PHI[LKER]_.PB; END ELSE BEGIN !**[524] MATCHER @4241 SJW 17-DEC-76 ![524] CALL STPRECLUDE BEFORE CMNMAK CHANGES NEG FLAGS SO HASH IN ![524] STPRECLUDE CAN FIND THE SKEW PIECE OF TREE %[524]% !PRECLUDE IF NECESSARY %[524]% STPRECLUDE(.PHI[LKER]); T_CMNMAK(.PHI[LKER],.PHI[NEDSANEG],.PHI); !MAKE A CMNSUB PC_.PHI[LKER]; END; !FIX UP TREE END ELSE BEGIN !SHAPE IS STRAIGHT !MAKE CMNSUB NODE !**;[371], MATCHER @4161, DCE, 14-APR-76 !**;[371], TAKE INTO CONSIDERATION THE NON-SKEWED CASE %[371]% IF .PHI[NBRCH] THEN %[371]% BEGIN %[371]% T_CMNMAK(.CNODE,.NAN,.PHI); ![371] IF FIRST NODE WAS SKEWED, MAKE THE ONE ![371] WE *KEEP* STRAIGHT. ALSO PRECLUDE OTHERS ![371] PRECLUDED BY THIS MATCH. %[371]% NARY2(.PHI[LKER]) %[371]% END %[371]% ELSE %[371]% BEGIN !**[524] MATCHER @4262 SJW 17-DEC-76 ![524] CALL STPRECLUDE BEFORE CMNMAK CHANGES THE NEG FLAGS %[524]% ![371] FIRST NODE WAS STRAIGHT %[524]% ![371] BUT STILL HAVE THE COUNT HASSLE %[524]% %[371]% STPRECLUDE(.PHI[LKER]); %[371]% T_CMNMAK(.PHI[LKER], %[371]% .PHI[NEDSANEG],.PHI); %[371]% END; %[371]% PC_.PHI[LKER]; %[371]% PHI[LKER]_.CNODE END; !FIX UP EXPRESSION PTRS !PC IS POINTER TO THE EXPRESSION QQ_CMNLNK(.T,.PC,IF .PHI[NBRCH] THEN SKEW ELSE STGHT,.PHI[NEDSANEG],.PHI); !QQ POINTS TO *PARENT* ON RETURN FROM CMNLNK IF NOT CHK4OPS(.CNODE) THEN NEXTUP(.QQ); END ELSE PHI[USECNT]_.PHI[USECNT]+1; !USECNT ATR 1 !IF THIS IS A SKEWED TREE DELETE !HASH ENTRIES PRECLUDED BY THIS MATCH IF .SHAPE EQL SKEW THEN NARY2(.CNODE) ELSE STPRECLUDE(.CNODE); T_.PHI[TEMPER]; !POINT TO TEMP FOR SUBSTITUTION !LINK UP THE COMMON SUB EXPRESSION (CURRENT ONE) CMNLNK(.T,.CNODE,.SHAPE,.NAN,.PHI); END; !MATCHER !********************************* ROUTINE CMNLNK(T,CNODE,SHAPE,NAN,PHI)= BEGIN EXTERNAL LOKCALST,BACKST,ARGCONE; !LINK UP THE COMMON SUB-EXPRESSION IN ITS PLACE MAP PHAZ2 QQ; MAP BASE CNODE:PHI:T; EXTERNAL MAKPR1,SETNEG,SAVSPACE; EXTERNAL CHOSEN,GLOBREG,ITMCT,SPECCASE; OWN OLDT,NEGT; LABEL ADJCTL; T[EXPRUSE]_.PHI[USECNT]; !INITIALIZE FLAG TO 0 FLAG_0; IF .SHAPE EQL SKEW THEN BEGIN CNODE[A2NEGFLG]_0; IF .NAN THEN BEGIN CNODE[ARG2PTR]_MAKPR1(.CNODE,NEGNOT,NEGOP,.CNODE[VALTYPE],0,.T); CNODE[A2VALFLG]_0; END ELSE BEGIN CNODE[ARG2PTR]_.T; CNODE[A2VALFLG]_1; END; !THE TREE LOOKSE LIKE THIS ! *(CNODE) ! * * !*(QQ) *(JUST BECOME T) ! *(QQ) ! * * ! *(WILL BECOME QQ WE CARE ABOUT) ! *(WILL GO AWAY) QQ_.CNODE[ARG1PTR]; !SAVE DEFINITION POINT. IF QQ[ARG1PTR] IS NOT !AN EXPRESSION THEN THIS BECOMES THE DEFINITION POINT !OF THE DATAOPR, ETC. TS_.QQ[DEFPT1]; !THERE IS YET ANOTHER HASSLE.****NEG/NOT FLGS !WE MUST MOVE THEM UP IF POSSIBLE. THE CONDITIONS ARE !IF NEG IS SET AND CNODE DOESNT HAVE NOT SET, COMPLEMENT !NEG IN PARENT ELSE BUILD NEG NODE AND INSERT. THE !SAME IS TRUE FOR NOTS. SET REFERS TO THE ARG1FLGS OF !THE TOP ONE OF THE QQ NODES IN THE ABOVE DIAGRAM. IF .QQ[A1NEGFLG] THEN BEGIN IF NOT .CNODE[A1NOTFLG] THEN BEGIN CNODE[A1NEGFLG]_NOT .CNODE[A1NEGFLG]; QQ_.QQ[ARG1PTR]; END ELSE QQ_MAKPR1(.CNODE,NEGNOT,NEGOP,.QQ[VALTYPE],0,.QQ); END ELSE IF .QQ[A1NOTFLG] THEN BEGIN IF NOT .CNODE[A1NEGFLG] THEN BEGIN CNODE[A1NOTFLG]_NOT .CNODE[A1NOTFLG]; QQ_.QQ[ARG1PTR]; END ELSE QQ_MAKPR1(.CNODE,NEGNOT,NOTOP,.QQ[VALTYPE],0,.QQ); END ELSE QQ_.QQ[ARG1PTR]; CNODE[ARG1PTR]_.QQ; !SET DEFINITION POINT OF NODE JUST SUBSTITUTED CNODE[DEFPT2]_.PHI[STPT]; !NOW, DEPENDING ON WHETHER OR NOT QQ IS A !DATAOPR OR CMNSUB SET DEFPT1, VALFLAGS AND !PARENT POINTER IF .QQ[OPRCLS] EQL DATAOPR OR .QQ[OPRCLS] EQL CMNSUB THEN BEGIN CNODE[DEFPT1]_.TS; CNODE[A1VALFLG]_1; END ELSE BEGIN !AN EXPRESSION CNODE[DEFPT1]_.QQ[DEFPT1]; QQ[PARENT]_.CNODE; END; !MAKE SURE QQ POINTS TO CNODE PARENT BEFORE !RETURN AS THIS FEATURE IS USED BY NEXTUP !IN THIS SKEWED CASE THE EXPRESSION WE WANT !TO EXAMINE IS THE ONE IN WHICH THE SUBSTITUTION HAS !OCCURRED. QQ_.CNODE; END ELSE BEGIN !HERE, ONCE AGAIN, WE HAVE THE SPECAIL LOCAL (SINGLE VARIABLE) CASE. !CNODE IS A POINTER TO THE EXPRESSION AND WILL !ITSELF FUNCTION AS THE PARENT !NO OTHER CASE LOOKS FOR COMMON SUBS IN AN ARRAYREF !OR RELATIONAL.****THIS IS AN IMPORTANT CONCEPT****. !THE GLOBAL CASE DOES LOOK FOR RELATIONALS SO AN !ADDITIONAL TEST ON BACKST IS ALSO NECESSARY !SAVE VALUE OF T OLDT_.T; IF (.CNODE[OPRCLS] EQL ARRAYREF OR .CNODE[OPRCLS] EQL RELATIONAL) AND .BACKST NEQ 0 THEN BEGIN QQ_.CNODE; CNODE_.PHI[LKER]; !IF IT IS A RELATIONAL WE MUST !SET A SPECIAL FLAG SO THAT !THE REGISTER ALLOCATOR WILL KNOW THAT !IT MAY HAVE TO BE MOVED TO ANOTHER !REGISTER IF THIS IS AN AOBJN LOOP. IF .QQ[OPRCLS] EQL RELATIONAL THEN T[CSFULLWDFLG]_1; END ELSE BEGIN QQ_.CNODE[PARENT]; !IF T IS A VARIABLE (THIS IS THE GLOBAL CASE9 !DONT SET THE PARENT TO T. DONT SET THE PARENT !AT ALL. IF .T[OPRCLS] EQL CMNSUB THEN CNODE[PARENT]_.T; END; IF .NAN THEN NEGT_ MAKPR1(.QQ,NEGNOT,NEGOP,.CNODE[VALTYPE],0,.T); IF .QQ[OPRCLS] EQL STATEMENT THEN BEGIN IF .NAN THEN IF SETNEG(.QQ,0) THEN ELSE (T_.NEGT;FLAG_1;); REPLACARG(.QQ,.CNODE,.T); IF .T[IDDOTO] EQL SIXBIT ".O" THEN IF .QQ[SRCID] EQL ASGNID THEN IF .QQ[SRCOPT] NEQ 0 THEN QQ[OPDEF]_.PHI[STPT]; END ELSE IF .QQ[OPRCLS] EQL FNCALL THEN BEGIN LOCAL ARGUMENTLIST AG; IF .NAN THEN (T_.NEGT;FLAG_1;); AG_.QQ[ARG2PTR]; !SET UP PARMS INCASE WE HAVE !TO CALL LEAFSUBSTITUTE TO LOCATE IT ITMCT_1; GLOBREG[0]_.CNODE; CHOSEN[0]_.T; SPECCASE_0; LOKCALST(.AG,.AG[ARGCOUNT],.CNODE,.T); !PUT DEFINITION POINT INTO NODE IF !APPROPRIATE IF ARGCONE(.QQ) THEN QQ[DEFPT2]_.PHI[STPT]; END ELSE !**;[620], CMNLNK @4431, DCE, 22-SEP-77 !**;[620], IF THIS IS AN IOLSCLS NODE, WE HAVE TO BE VERY CAREFUL !**;[620], WITH WHERE WE TIE IN THE POINTER! %[620]% IF .QQ[OPRCLS] EQL IOLSCLS THEN %[620]% BEGIN %[620]% IF .NAN THEN (T_.NEGT; FLAG_1); %[620]% IF .QQ[SCALLELEM] EQL .CNODE %[620]% THEN QQ[SCALLELEM]_.T %[620]% ELSE IF .QQ[SCALLCT] EQL .CNODE %[620]% THEN QQ[SCALLCT]_.T; %[620]% END ELSE IF .QQ[ARG1PTR] EQL .CNODE AND .QQ[OPRCLS] NEQ ARRAYREF THEN BEGIN IF .NAN THEN IF SETNEG(.QQ,1) THEN ELSE (T_.NEGT;FLAG_1;); QQ[ARG1PTR]_.T; IF .T[OPRCLS] EQL CMNSUB OR .T[OPRCLS] EQL DATAOPR THEN QQ[A1VALFLG]_1; QQ[DEFPT1]_.PHI[STPT]; END ELSE BEGIN IF .NAN THEN IF SETNEG(.QQ,0) THEN ELSE (T_.NEGT;FLAG_1;); QQ[ARG2PTR]_.T; IF .T[OPRCLS] EQL CMNSUB OR .T[OPRCLS] EQL DATAOPR THEN QQ[A2VALFLG]_1; QQ[DEFPT2]_.PHI[STPT]; END; !ONE MORE THING. IF THE PARENT IS !A CONTROL TYPR BOOLEAN WE HAVE TO CHANGE IT !TO CONTROL, CUZ CODE GENERATION CANNOT HANDLEE !A VALUE UNDER A BOOLEAN OR TYPE CONTROL T_.QQ; ADJCTL: WHILE .T[OPRCLS] EQL BOOLEAN AND .T[VALTYPE] EQL CONTROL DO BEGIN !CHANGE TO LOGICAL T[VALTYPE]_LOGICAL; !LOOK AT NEXT PARENT T_.T[PARENT]; !CHECK FOR ORPHAN IF .T EQL 0 THEN LEAVE ADJCTL; END; !RESTORE NODE SPACE FREED, IF ANY IF .NAN THEN IF .FLAG THEN ELSE SAVSPACE(EXSIZ-1,.NEGT); T_.OLDT; IF .T[OPRCLS] EQL CMNSUB THEN BEGIN !THE CHECK FOR THE VALFLG BEING SET ON !A CMNSUB NODE IS EQUIVALENT TO THE !SPECIAL CASE CHECK FOR THE LOCAL !UNARY SUBSCRIPT OR RELATIONAL. !IT IS CLEAR THAT THE SPACE FOR A !SYMBOL TABLE NODE DOES NOT GET FREED. IF .T[ARG2PTR] NEQ .CNODE AND NOT .T[A2VALFLG] THEN SAVSPACE(EXSIZ-1,.CNODE); END; END; .QQ END; ROUTINE CHKHAIR(CNODE,PHI,SHAPE)= BEGIN LOCAL BASE ARGNODE; ! !CHECK NODE FOR HAVING ANOTHER COMMON SUB-EXPRESSION UNDER IT !IF IT DOES SET CMNUNDER FLAG IN HASH TABLE NODE. EXTERNAL TOP,LENTRY; MAP BASE TOP:PA; MAP PEXPRNODE CNODE:PHI; MACRO ARG1CHK= BEGIN ARGNODE_.CNODE[ARG1PTR]; IF .ARGNODE[OPRCLS] EQL CMNSUB OR .ARGNODE[IDDOTO] EQL SIXBIT".O" THEN PHI[CMNUNDER]_1; END$; MACRO ARG2CHK= BEGIN ARGNODE_.CNODE[ARG2PTR]; IF .ARGNODE[OPRCLS] EQL CMNSUB OR .ARGNODE[IDDOTO] EQL SIXBIT".O" THEN PHI[CMNUNDER]_1; END$; MACRO CHKBOTH= BEGIN ARG2CHK; IF .SHAPE EQL SKEW THEN BEGIN CNODE_.CNODE[ARG1PTR]; ARG2CHK; END ELSE ARG1CHK; END$; CASE .CNODE[OPRCLS] OF SET !BOOLEAN BEGIN CHKBOTH; END; !DATAOPR RETURN; !RELATIONAL BEGIN CHKBOTH; END; !FNCALL RETURN; !ARITHMETIC BEGIN CHKBOTH; END; !TYPCNV ARG2CHK; !ARRAYREF RETURN; !CMNSUB RETURN; !NEGNOT ARG2CHK; !SPECOP ARG1CHK; !FIELDREF RETURN; !STORECLS RETURN; !RECONTENTS RETURN; !LABOP RETURN; !STATEMENT RETURN; !IOLSCLS RETURN; !INLINFN BEGIN ARG1CHK; IF .CNODE[ARG2PTR] NEQ 0 THEN ARG2CHK; END TES; END; MACRO REVARG= ENTRYP[HA1]_.CNODE[ARG2PTR]; ENTRYP[HDEF1]_.CNODE[DEFPT2]; ENTRYP[HA2]_.CNODE[ARG1PTR]; ENTRYP[HDEF2]_.CNODE[DEFPT1];$, REGARG= ENTRYP[HA1]_.CNODE[ARG1PTR]; ENTRYP[HDEF1]_.CNODE[DEFPT1]; ENTRYP[HA2]_.CNODE[ARG2PTR]; ENTRYP[HDEF2]_.CNODE[DEFPT2];$, SREVARG= ENTRYP[HA1]_.CNODE[ARG2PTR]; ENTRYP[HDEF1]_.CNODE[DEFPT2]; ENTRYP[HA2]_.QQ[ARG2PTR]; ENTRYP[HDEF2]_.QQ[DEFPT2];$, SREGARG= ENTRYP[HA1]_.QQ[ARG2PTR]; ENTRYP[HDEF1]_.QQ[DEFPT2]; ENTRYP[HA2]_.CNODE[ARG2PTR]; ENTRYP[HDEF2]_.CNODE[DEFPT2];$; ! !******************************************** ! OWN TALLY; GLOBAL ROUTINE HASHIT(CNODE,SHAPE)= BEGIN EXTERNAL LOOPNO,REDEFPT; OWN PHAZ2 ENTRYP; MAP PHAZ2 CNODE; !CREATE HASH TABLE ENTRY FOR LOOKUP; THE GLOBAL ENTRY IS USED. !ENTRY IS FILLED WITH THE HASH KEY ELEMENTS. THESE ARE !THE OPERATOR, ARGUMENTS(S) AND DEFINITION POINTS. !THE MACROS PRECEEDING THIS ROUTINE HELP ASSURE THAT !ARGUMENTS ARE IN THEIR PROPER ORDER. !NODE:*******NO DOT ON ASSIGNMENT TO ENTRYP ENTRY_0; ENTRYP_ENTRY; ENTRY+1_0; NAN_0; IF .FLGREG AND NOT .IMPLDO THEN REDEFPT(.CNODE,.SHAPE); ENTRYP[BLKID]_.LOOPNO; CASE .SHAPE OF SET ! !UNARY ! !TYPECNV, ARRAYREF WITH SIMPLE VARIABLE AS RESULTANT SUBSCRIPT !ALSO LIBRARY FUNCTIONS OF A SINGLE ARGUMENT !ALSO SPECIAL OPERATORS WHICH ARE ARG1 TYPES INSTEAD OF ARG2. BEGIN !IF THE ITEM IS A VARIABLE (THIS IS SPECIAL ARRAYREF CASE IF .CNODE[OPRCLS] EQL DATAOPR AND .CNODE[OPERSP] NEQ CONSTANT THEN BEGIN ENTRYP[HOP]_VARFL; ENTRYP[HDEF1]_0; ENTRYP[HA2]_.CNODE; ENTRYP[HDEF2]_0; ENTRYP[HA1]_0; END ELSE !IT IS NOT THE LOCAL SPECIAL CASE !SEE IF ITS AN ARRAYREF (GLOBAL ONLY) IF .CNODE[OPRCLS] EQL ARRAYREF THEN BEGIN ENTRYP[HOP]_.CNODE[OPERATOR]; !FUDGE THE OFFSET INTO THE BLOCK ID ENTRYP[BLKID]_.CNODE[TARGADDR]; !BUT BE SURE THE EMPTY BIT IS OFF ENTRYP[EMPTY]_0; REGARG; END ELSE !NOT AN ARRAYREF, TRY FUNCTION REFERENCE IF .CNODE[OPRCLS] EQL FNCALL THEN BEGIN REGISTER ARGUMENTLIST AG; ENTRYP[HOP]_.CNODE[OPERATOR]; ENTRYP[HA1]_.CNODE[ARG1PTR]; ENTRYP[HDEF1]_0; AG_.CNODE[ARG2PTR]; ENTRYP[HA2]_.AG[1,ARGNPTR]; ENTRYP[HDEF2]_.CNODE[DEFPT2]; END ELSE !NOT A FUNCTION CALL EITHER. CHECK FOR !SPECIAL OPERATOR IF .CNODE[OPRCLS] EQL SPECOP THEN BEGIN IF .CNODE[A1NEGFLG] THEN NAN_1; ENTRYP[HOP]_.CNODE[OPERATOR]+.CNODE[A1NOTFLG]; REGARG; END ELSE !NOW TREAT EVERYONE THE SAME !(TYPECNV AND NEGNOT BEGIN IF .CNODE[A2NEGFLG] THEN NAN_1; ENTRYP[HOP]_.CNODE[OPERATOR]+.CNODE[A2NOTFLG]; REGARG; END; END; ! !STRAIGHT ! ! OP ! * * ! * * !DATA DATA BEGIN IF .CNODE[OPRCLS] EQL ARITHMETIC THEN BEGIN !ARITHMETIC NODES ARE A SPECIAL CASE !BECAUSE THE SKELETON OPTIMIZER HAS !ELIMINATED SUBTRACT NODES IN FAVOR OF !ADDS WITH PROPER NEG FLAGS SET. WE !ALSO WISH TO RECOGNIZE A-B AND B-A AS !THE SAME EXPRESSION (PLUS NEGATE ON ONE OF THEM). !TALLY IS THE XOR OF THE NEGATE FLAGS !PRESENT IN THE NODE. TALLY_.CNODE[A1NEGFLG] XOR .CNODE[A2NEGFLG]; IF .CNODE[OPR1] EQL ADDOPF THEN !ADDS ARE A SPECIAL CASE BEGIN !IN ALL CASES THE EXPRESSION WILL BE !CONSIDERED TO BE A-B. THIS IS !TALLY =1 AND A2NEGFLG SET. TALLY = 1 !AND A1NEGFLG SET IS B-A WHICH NEEDS !A NEGATION (NAN SET). ! 0 NAN !----- ----- !A+B -(A+B) !A-B -A+B==B-A NAN_.CNODE[A1NEGFLG]; ENTRYP[HOP]_.CNODE[OPERATOR]+.TALLY+ .CNODE[A1NOTFLG]^1+.CNODE[A2NOTFLG]^2; !MAKE SURE ONCE AGAIN THAT ARGS ARE !IN THE CORRECT ORDER. IN GENERAL, !THEY ARE PROPERLY ORDERED BY CANONICALIZATION !WHEN NEWLY FOUND COMMON SUBS ARE INVOLVED !WE MAY NEED TO ORDER THEM HERE. IF .CNODE[ARG1PTR] GTR .CNODE[ARG2PTR] THEN BEGIN REVARG; IF .TALLY THEN NAN_NOT .NAN; END ELSE !ARGS ARE ALREADY IN RIGHT ORDER BEGIN REGARG; END; END ELSE !END OF ADD OPERATION CASE BEGIN NAN_.TALLY; ENTRYP[HOP]_.CNODE[OPERATOR]+ .CNODE[A1NOTFLG]^1+.CNODE[A2NOTFLG]; !MULTIPLY IS ALSO SOMEWHAT SPECIAL IF .CNODE[OPR1] EQL MULOPF THEN BEGIN !CHECK ARG ORDER AGAIN IF .CNODE[ARG1PTR] GTR .CNODE[ARG2PTR] THEN BEGIN REVARG; END ELSE !ARGS IN PRDER BEGIN REGARG; END; END ELSE !NOT A MULTIPLY BEGIN REGARG; END; END; !END OF NOT ADD BUT STILL ARITHMETIC END ELSE !END OF ARITHMETIC BEGIN NAN_0; ENTRYP[HOP]_.CNODE[OPERATOR]+ .CNODE[A1NOTFLG]^1+.CNODE[A2NOTFLG]; REGARG; END; END; !END OF STRAIGHT CASE ! !SKEWED TREES ! ! OP(CNODE) ! * * ! * * !OP(QQ) DATA ! * ! * ! DATA ! BEGIN QQ_.CNODE[ARG1PTR]; IF .CNODE[OPRCLS] EQL ARITHMETIC THEN BEGIN !ARITHMETIC NODE !TALLY CONTAINS THE NUMBER OF NEGATIVES ON THE EXPRESSION TALLY_.CNODE[A2NEGFLG] XOR .QQ[A2NEGFLG]; IF .CNODE [OPR1] EQL ADDOPF THEN BEGIN !AN ADD ENTRYP[HOP]_.CNODE[OPERATOR]+.TALLY +.CNODE[A1NOTFLG]^1+.CNODE[A2NOTFLG]^2; !TALLY AND A NEGATE (GLAG) ON THE SECOND !NODE DETERMINE IF A NEGATE IS NEEDED !ON THE COMMON SUB. NAN_.QQ[A2NEGFLG]; !INSURE ARGS ARE ORDERED BY SYMBOL TABLE ADDRESS IF .QQ[ARG2PTR] GTR .CNODE[ARG2PTR] THEN BEGIN !THEY NEED SWITCHING SREVARG; IF .TALLY THEN NAN_NOT .NAN; END ELSE !THEY DONT NEED SWITCHING BEGIN SREGARG; END; END ELSE !NOT AN ADD BEGIN NAN_.TALLY; ENTRYP[HOP]_.CNODE[OPERATOR] +.CNODE[A1NOTFLG]^1+.CNODE[A2NOTFLG]; IF .CNODE[OPR1] EQL MULOPF THEN BEGIN !A MULTIPLY !WORRY ABOUT ARG ORDER AGAIN IF .QQ[ARG2PTR] GTR .CNODE[ARG2PTR] THEN BEGIN !NEED REORDERING SREVARG; END ELSE BEGIN !NO REORDERING NEEDED SREGARG; END END ELSE !NOT MULTIPLY BEGIN SREGARG; END END; END ELSE !END ARITHMETIC BEGIN !NOT ARITHMETIC ENTRYP[HOP]_.CNODE[OPERATOR] !**;[566], HASHIT @4816 (IN NOT ARITHMETIC), DCE, 4-MAY-77 !**;[566], CHECK ON THE CORRECT FLAGS FOR HASHING UNIQUELY %[566]% +.QQ[A2NOTFLG]^1+.CNODE[A2NOTFLG]; SREGARG; END; END !END SKEWED TREE CASE TES; END; !HASHIT !**************************************** EXTERNAL CHKDOMINANCE; ROUTINE XPUNGE(CNODE,SHAPE)= BEGIN LABEL FIND; EXTERNAL BACKST; !TREE HAS BEEN WALKED TO THE LEAF*OPERATOR*LEAF !POINT. THE EXPRESSION WILL NOW BE HASHED, ETC. MAP PEXPRNODE CNODE; !THE LOCAL AND GLOBAL CASES ARE DISTINGUISHED HERE !BY A TEST ON THE VALUE OF BACKST. BACKST MUST BE !ZERO IN THE GLOBAL CASE. THE CHECK IS NECESSARY SINCE !THE GLOBAL CASE REQUIRES MUCH CHECKING NOT NECESSARY IN THE !LOCAL CASE. IF .BACKST NEQ 0 OR .IMPLDO THEN !LOCAL CASE OR !I/O OPTIMIZER CASE BEGIN !**;[427], XPUNGE @4777, DCE, 19-AUG-76 !**;[427], WE CANNOT HANDLE SHAPES GREATER THAN SKEW HERE, !**;[427], FOR THERE IS NO SUCH CODE IN HASHIT. TO ADD !**;[427], CODE FOR THIS CASE, WE COULD USE CHKDOMINANCE AS !**;[427], A TEMPLATE, BUT THE CODE IS EXTENSIVE. FOR NOW !**;[427], SIMPLY DO NOT ATTEMPT TO HANDLE CASES WITH !**;[427], SHAPE GREATER THAN SKEW. AN EXAMPLE !**;[427], IS: READ() (A(B(I),J),C(B(I),J),J=1,10) %[427]% IF .SHAPE GTR SKEW THEN RETURN; HASHIT(.CNODE,.SHAPE); PHI_TBLSRCH(); IF .FLAG THEN MATCHER(.CNODE,.SHAPE,.NAN,.PHI) ELSE BEGIN PHI_ MAKETRY(.PHI,.CNODE,.SHAPE); IF .SHAPE EQL SKEW THEN PHI[NBRCH]_1; IF .NAN THEN PHI[NEDSANEG]_1; !**;[405], XPUNGE @4781, DCE, 28-MAY-76 !**;[405], FIND DEFINITION POINTS CORRECTLY FOR STAR1 AND !**;[405], STAR2 CASES. THIS MAY HAVE TO BE CHANGED IF !**;[405], MORE GENERAL EXPRESSIONS ARE ALLOWED IN I/O LISTS !**;[405], FOR NOW IT CATCHES THE CASE (A(P(I)),I=1,4) WHERE !**;[405], A IS A FORMAL PARAMETER BEING PASSED %[405]% IF NOT .IMPLDO THEN PHI[STPT]_0 !LOCAL CASE %[405]% ELSE BEGIN ! I/O LIST CASE %[405]% LOCAL CN,DF1,DF2; %[405]% MAP PEXPRNODE CN; %[405]% PA_.LENTRY; !**;[405], HERE IS THE MAIN CHANGE - WE MUST DROP DOWN ONE !**;[405], NODE PRIOR TO GRABBING THE DEF POINTS FOR STAR1 !**;[405], AND STAR2 SHAPES - CN POINTS TO THE NODE WE WANT %[405]% CN_IF .SHAPE EQL STAR1 THEN .CNODE[ARG1PTR] %[405]% ELSE IF .SHAPE EQL STAR2 THEN .CNODE[ARG2PTR] %[405]% ELSE .CNODE; %[405]% DF1_.CN[DEFPT1]; DF2_.CN[DEFPT2]; !**;[602], XPUNGE @4881, DCE, 9-AUG-77 !**;[602], IF SHAPE IS SKEW, WE NEED TO GET THE CORRECT DEFINITION !**;[602], POINT FOR THE LEFT HAND NODE. AN EXAMPLE CASE WHICH !**;[602], CAUSES THIS TO HAPPEN IS: A(B(L+I-1)),I=J,K !**;[602], WHERE B IS A FORMAL ARRAY! %[602]% IF .SHAPE EQL SKEW %[602]% THEN (CN_.CNODE[ARG1PTR]; %[602]% DF1_.CN[DEFPT2]); %[405]% IF .DF1 EQL .DF2 THEN PHI[STPT]_.DF1 !DONE %[405]% ELSE BEGIN %[405]% P_IF .DF1 EQL 0 THEN 1 ELSE 0; %[405]% IF .DF2 EQL 0 THEN P_.P+2; %[405]% FIND: WHILE 1 DO %[405]% BEGIN %[405]% IF NOT .P<0,1> THEN %[405]% IF .PA EQL .DF1 THEN P_.P+1; %[405]% IF NOT .P<1,1> THEN %[405]% IF .PA EQL .DF2 THEN P_.P+2; %[405]% IF .P EQL 3 THEN LEAVE FIND; %[405]% PA_.PA[CLINK] %[405]% END; %[405]% PHI[STPT]_.PA %[405]% END %[405]% END %[405]% END END ELSE CHKDOMINANCE(.CNODE,.SHAPE); !GLOBAL CASE END; ! !**************************************************** ! ! !*************************************************** ! FORWARD LOCELMIO; ROUTINE ELIM(STMT)= BEGIN MAP PHAZ2 STMT; EXTERNAL IOGELM; !WALK I/O LISTS EXTERNAL IOCLEAR; !COLLAPSE I/O LISTS IF GCALLSLFLG IS SET EXTERNAL CSTMNT,BACKST,TOP,LEND,LOOP; MAP BASE TOP; MAP BASE BACKST; !CONTROLLING ROUTINE AT THE STATEMENT LEVEL FOR !COMMON SUB-EXPRESSION ELIMINATION, BOTH GLOBAL !AND LOCAL. ONLY STATEMENTS MENTIONED EXPLICITLY !IN THIS ROUTINE CAN EVEN POTENTIALLY HAVE !COMMON SUB-EXPRESSIONS.THOSE STATEMENT TYPES ARE: !ASSIGNMENT,LOGICAL IF, DO, ARITHMETIC IF,READ, WRITE. !ASSIGNMENT STATEMENTS IF .STMT[SRCID] EQL ASGNID THEN BEGIN PAE_.STMT[LHEXP]; IF .PAE[OPRCLS] EQL ARRAYREF THEN REA(.PAE); !SPECIAL CHECK FOR VARIABLE INITIALIZATION IN THE GLOBAL !CASE IF .STMT[A2VALFLG] THEN BEGIN IF .FLGREG THEN IF .STMT[SRCOPT] NEQ 0 THEN IF .LOOP EQL 0 THEN IF .STMT[OPDEF] EQL .LENTRY THEN CHKINIT(.STMT[RHEXP]); END ELSE REA(.STMT[RHEXP]); END; !LOGICAL IF IF .STMT[SRCID] EQL IFLID THEN BEGIN REA(.STMT[LIFEXPR]); IF NOT .FLGREG THEN BEGIN !THE SPECIAL CHECK IS NECESSARY TO !AVOID PROCESSING THE STATEMENT !FOLLOWING THE LOGICAL IF TWICE IN THE !GLOBAL CASE. THE TRUE BRANCH IS ON !THE PROCESSING LIST AS A SPEARATE ENTITY !BY ITSELF IN THE GLOBAL CASE. !HOOK ALL LOCALS FOUND SO FAR TO THE !IF PART LOCLDEPD(); STMT[SRCCOMNSUB]_.BACKST[SRCLINK]; BACKST[SRCLINK]_0; LOCLNK_0; CSTMNT_.STMT[LIFSTATE]; ELIM(.STMT[LIFSTATE]); END; END; !DO STATEMENT IF .STMT[SRCID] EQL DOID THEN BEGIN REA(.STMT[DOLPCTL]); END; !ARITHMETIC IF IF .STMT[SRCID] EQL IFAID THEN BEGIN REA(.STMT[AIFEXPR]); END; !I/O STATEMENTS IF .STMT[SRCID] GEQ READID AND .STMT[SRCID] LEQ REREDID THEN %[V5]% IF .FLGREG AND NOT .GLOBELIM2 THEN IOGELM(.STMT) ELSE IF .GCALLSLFLG THEN IOCLEAR(.STMT) ELSE LOCELMIO(.STMT); END; !ELIM ! !*************************************************** ! ! EXTERNAL BACKST; MAP PEXPRNODE BACKST; ! OWN SAVCSTMNT; GLOBAL ROUTINE LOCELIM(STMT)= BEGIN EXTERNAL CSTMNT,LOOPNO; MAP PEXPRNODE STMT:CSTMNT; !************************************ !CONTROL FOR LOCAL COMMONSUB-EXPRESSION ELIMINATION !************************************** SAVCSTMNT_.CSTMNT; LOCLNK_0; STHASCMN_0; BACKST[SRCLINK]_0; LOOPNO_.CSTMNT[SRCISN]; ELIM(.STMT); IF .STHASCMN THEN BEGIN LOCLDEPD(); CSTMNT[SRCOPT]_.BACKST[SRCLINK]; END; CSTMNT_.SAVCSTMNT; !THE ABOVE STATEMENT EITHER ZEROES THE POINTER TO COMMON !SUB-EXPRESSIONS OR SETS IT TO POINT TO THEM CORRECTLY END; ! !******************************************************** ! EXTERNAL EHASH; ROUTINE REA(STKPAE)= !PAE IS AN EXPRESSION POINTER BEGIN !THIS ROUTINE IS NAMED IN HONOR OF REA RAILWAY EXPRESS. !THIS IS WHERE WE ATTEMPT TO RAILROAD EVERYTHING THROUGH! !*********************************** ! !AS IS NOT OBVIOUS IT DEALS WITH COMMON EXPRESSION ELIMINATION. !IT DOES THE BASIC TREE WALK THROUGH THE TREES. !IT IS CALLED BY ELIM AND CALLS XPUNGE TO HASH AND MATCH !THE PHILOSOPHY BEHIND EACH SECTON OF CODE IS THE SAME. !WALK THE TREE BASED ON THE SETTING OF THE VALFLGS (SAYS !NODE UNDER HERE IS LEAF IS SET). WALK BRANCHES BEFORE LOOKING !AT CURRENT NODE ITSELF. !ALSO CHECK FOR THE SKEWED TREE CASE. EXTERNAL FNARRAY; REGISTER PHAZ2 PAE; PAE_.STKPAE; STHASCMN_1; CASE .PAE[OPRCLS] OF SET ! !BOOLEAN ! BEGIN IF NOT .PAE[A1VALFLG] THEN REA(.PAE[ARG1PTR]); IF NOT .PAE[A2VALFLG] THEN REA(.PAE[ARG2PTR]); IF .PAE[A1VALFLG] AND .PAE[A2VALFLG] THEN XPUNGE(.PAE,STGHT) ELSE BEGIN QQ_.PAE[ARG1PTR]; IF .QQ[OPERATOR] EQL .PAE[OPERATOR] AND !N-ARY WITH LEAVES .QQ[A2VALFLG] AND .PAE[A2VALFLG] AND NOT .QQ[PARENFLG] THEN XPUNGE(.PAE,PSKEW); END; !ELSE PART SKEWED TREE END; !BOOLEAN CLASS OPERATORS ! !DATAOPR ! RETURN; !DO NOTHING ! !RELATIONAL ! BEGIN IF NOT .PAE[A1VALFLG] THEN REA(.PAE[ARG1PTR]); IF NOT .PAE[A2VALFLG] THEN REA(.PAE[ARG2PTR]); !LOCAL CASE TEST OB BACKST !GLOBAL CASE BACKST **MUST** BE ZERO (0) IF .BACKST NEQ 0 THEN BEGIN VARHOLDER_.PAE; IF .PAE[A1VALFLG] THEN BEGIN QQ_.PAE[ARG1PTR]; IF .QQ[OPRCLS] EQL DATAOPR AND .QQ[OPERSP] NEQ CONSTANT THEN XPUNGE(.QQ,UNARY); END; IF .PAE[A2VALFLG] THEN BEGIN QQ_.PAE[ARG2PTR]; IF .QQ[OPRCLS] EQL DATAOPR AND .QQ[OPERSP] NEQ CONSTANT THEN XPUNGE(.QQ,UNARY); END; END ELSE !GLOBAL OPTIMIZER SHOULD FIND THEM !**;[520], REA @5009 (5098 IN VERSION 5), DCE, 19-NOV-76 !**;[520], DO NOT CONSIDER FOR COMMON SUBEXPRESSIONS RELATIONAL !**;[520], EXPRESSIONS INVOLVING NEG FLAGS. TO ALLOW THIS WILL CAUSE !**;[520], EXPRESSIONS LIKE A .GT. B AND -A .GT. B TO BE !**;[520], CONSIDERED AS COMMON SUBS - CLEARLY WRONG! %[520]% IF(.PAE[A1NEGFLG] OR .PAE[A2NEGFLG]) THEN RETURN ELSE IF .PAE[A1VALFLG] AND .PAE[A2VALFLG] THEN XPUNGE(.PAE,STGHT); END; ! !FNCALL - FUNCTION CALL ! BEGIN LOCAL ARGUMENTLIST TMP; !STEP THROUGH ARGUMENTS. EACH ARGEUMENT HAS THE FUNCTION !NODE AS PARENT TMP_.PAE[ARG2PTR]; INCR I FROM 1 TO .TMP[ARGCOUNT] DO BEGIN QQ_.TMP[.I,ARGNPTR]; REA(.QQ); END; !IF OPTIMIZING GO OFF AND TRY FOR ARRAY REFS TOO IF .FLGREG THEN BEGIN FNARRAY(.PAE); RETURN; END; !!TRY TO ELIMINATE LIBRARY FUNCTIONS WITH 1 ARGUMENT IF ARGCONE(.PAE) THEN XPUNGE(.PAE,UNARY); END; !FNCALL ! !ARITHMETIC ! BEGIN IF NOT .PAE[A1VALFLG] THEN REA(.PAE[ARG1PTR]); IF NOT .PAE[A2VALFLG] THEN REA(.PAE[ARG2PTR]); !TRY ARRAY REFERENCES IF .FLGREG THEN BEGIN IF NOT .PAE[A1VALFLG] THEN A1ARREF(.PAE); IF NOT .PAE[A2VALFLG] THEN A2ARREF(.PAE); END; !NOW REGULAR SKEWED %[V5]% IF .PAE[A1VALFLG] AND .PAE[A2VALFLG] %[V5]% THEN BEGIN %[V5]% IF .FLGREG AND %[V5]% .PAE [OPERSP] NEQ DIVOP %[V5]% THEN BEGIN ! X OP .R -> .R OP X %[V5]% MACRO IDDOTR = 0,3,24,12$; %[V5]% REGISTER BASE T1; %[V5]% %[V5]% T1 _ .PAE [ARG2PTR]; %[V5]% IF .T1 [IDDOTR] EQL SIXBIT ".R" %[V5]% THEN BEGIN %[V5]% SWAPARGS (PAE); %[V5]% T1 _ .PAE [DEFPT1]; %[V5]% PAE [DEFPT1] _ .PAE [DEFPT2]; %[V5]% PAE [DEFPT2] _ .T1; %[V5]% END; %[V5]% END; %[V5]% XPUNGE (.PAE, STGHT); %[V5]% END ELSE BEGIN QQ_.PAE[ARG1PTR]; IF .QQ[OPR1] EQL .PAE[OPR1] AND .PAE[OPR1] NEQ DIVOPF AND NOT .QQ[PARENFLG] AND !N-ARY WITH LEAVES .QQ[A2VALFLG] AND .PAE[A2VALFLG] THEN XPUNGE(.PAE,PSKEW); !LOOK DOWN ONCE MORE IF .PAE[A1VALFLG] AND .PAE[A2VALFLG] THEN XPUNGE(.PAE,STGHT); END; END; ! !TYPCNV ! BEGIN IF NOT .PAE[A2VALFLG] THEN REA(.PAE[ARG2PTR]); IF .PAE[A2VALFLG] THEN XPUNGE(.PAE,UNARY); END; ! !ARRAYREF ! BEGIN IF .PAE[ARG2PTR] EQL 0 THEN RETURN; IF .PAE[A2VALFLG] AND .BACKST NEQ 0 THEN !SPECIAL CASE FOR LOCAL ONLY BEGIN VARHOLDER_.PAE; QQ_.PAE[ARG2PTR]; !ITS A NON-CONSTANT LEAF. CONSTANT LEAVES SHOULD HAVE !BEEN FOLDED INTO THE OFFSET. IF .QQ[OPRCLS] EQL DATAOPR AND .QQ[OPERSP] NEQ CONSTANT THEN !THE NEG AND/OR NOT FLAGS CANNOT BE SET. !WE ARE NOT PREPARED TO HASH THEM. IN !GENERAL THIS WILL NOT PREVENT MUCH CUZ THE !FLAGS DONT MAKE A LOT OF SENSE ON THE SUBSCRIPT !ANYWAY. IF NOT .PAE[A2NEGFLG] AND NOT .PAE[A2NOTFLG] THEN XPUNGE(.QQ,UNARY); END ELSE REA(.PAE[ARG2PTR]); END; ! !CMNSUB ! RETURN; !SHOULDNT HAPPEN ! !NEGNOT ! BEGIN IF NOT .PAE[A2VALFLG] THEN REA(.PAE[ARG2PTR]); IF .PAE[A2VALFLG] THEN XPUNGE(.PAE,UNARY); END; ! !SPECOP ! BEGIN IF NOT .PAE[A1VALFLG] THEN REA(.PAE[ARG1PTR]); IF .PAE[A1VALFLG] THEN XPUNGE(.PAE,UNARY); END; ! !FIELDREF ! RETURN; !NOT IN RELEASE 1 ! !STORECLS ! RETURN; ! !REGCONTENTS ! RETURN; ! !LABOP ! RETURN; ! !STATEMENT ! RETURN; ! !IOLSCLS ! RETURN; !SEE REAIO ! !INLINFN ! BEGIN IF NOT .PAE[A1VALFLG] THEN REA(.PAE[ARG1PTR]); IF .PAE[A1VALFLG] THEN IF .PAE[ARG2PTR] EQL 0 THEN XPUNGE(.PAE,UNARY); IF NOT .PAE[A2VALFLG] THEN IF .PAE[ARG2PTR] NEQ 0 THEN REA(.PAE[ARG2PTR]); IF .PAE[A1VALFLG] AND .PAE[A2VALFLG] THEN XPUNGE(.PAE,STGHT); END; TES; END; ROUTINE REAIO(CLSTCALL)= BEGIN !EXAMINE THEN IOLSTCALL, E1LISTCALL, E2LISTCALL !FOR EXPRESSIONS TO HASH !CLSTCALL IS A POINTER TO AN I/O LIST. !WALK THAT TREE LOOKING FOR EXPRESSIONS TO EXPUNGE. MAP BASE CLSTCALL; LOCAL BASE P; IF .CLSTCALL[OPRCLS] EQL STATEMENT THEN RETURN; STHASCMN_0; CASE .CLSTCALL[OPERSP] OF SET !DATACALL BEGIN !LEGAL ONLY RECURSIVELY P_.CLSTCALL[DCALLELEM]; IF .P[OPRCLS] NEQ DATAOPR THEN REA(.P) END; ! !SLISTCALL BEGIN !LEGAL ONLY RECURSIVELY !NOTHING TO DO END; ! !IOLSTCALL BEGIN P_.CLSTCALL[IOLSTPTR]; WHILE .P NEQ 0 DO BEGIN REAIO(.P); P_.P[SRCLINK]; END; END; ! !E1LISTCALL ; !RELEASE >1 !E2LISTCALL ; !RELEASE >1 TES; END; !REAIO GLOBAL ROUTINE LOCELMIO(PO)= !CONTROL FINDING OF COMMON SUB EXPRESSIONS IN THE LOCAL CASE !(ONLY ONE DONE FOR RELEASE ONE) IN I/O LISTS. CALLED BU ELIM. !CALLS REAIO TO WALK TREES BEGIN MAP BASE PO; REGISTER BASE IOLSTT; EXTERNAL BACKST; MAP BASE BACKST; IF .BACKST EQL 0 THEN RETURN; !RESET THE LINKING POINTER FOR LOCAL GOMMON SUBS. !THIS PRECLUDES LOCELMIO FROM EVER BEING USED RECURSIVELY !(CORRECTLY, THAT IS). LOCLNK_0; !PO POINTS AT IO STATEMENT !IN RELEASE 1 THERE IS NEVER A COMMON SUB ON AN I/O !STATEMENT ITSELF SO WE WILL ZERO THE FIELD. THIS !ALSO HELPS MAKE SURE THE GLOBALLY USED FIELDS ARE CLEARED. PO[SRCOPT]_0; !ROUTINE DOES LOCAL ELIMINATION ON IOLSTCALL (RELEASE 1) !E1LISTCALL AND E2LISTCALL (RELEASE >1) IF .PO[IOLIST] NEQ 0 THEN BEGIN IOLSTT_.PO[IOLIST]; WHILE .IOLSTT NEQ 0 DO BEGIN IF .IOLSTT[OPRCLS] NEQ STATEMENT THEN BEGIN IF .IOLSTT[OPERSP] EQL IOLSTCALL THEN BEGIN REAIO(.IOLSTT); LOCLDEPD(); IOLSTT[SRCCOMNSUB]_.BACKST[SRCLINK]; BACKST[SRCLINK]_0; LOCLNK_0 END; END; IOLSTT_.IOLSTT[CLINK]; END; END; END; !THE FOLLOWING FEW ROUTINES ARE UTILITY ROUTINES FOR DEALING WITH !THE EXPRESSION HAS TABLE. ROUTINE SLINGHASH= BEGIN !CLEAN OUT THE EXPRESSION HASH TABLE MAP BASE PAE; DECR I FROM EHSIZ-1 TO 0 DO BEGIN PAE_.EHASH[.I]; WHILE .PAE NEQ 0 DO BEGIN PAE[EMPTY]_1; PAE_.PAE[CLINK]; END; END; END; GLOBAL ROUTINE TBLSRCH= BEGIN LABEL LOKER; MAP PEXPRNODE P; LOCAL T; !LOOK UP AN EXPRESSION IN THE EXPRESSION HASH TABLE. !THE ROUITNE HASHIT HAS FILLED IN THE GLOBAL ENTRY !WITH THE PROPER PARAMETERS. !RETURNS FLAG IF FOUND 1 !ELSE !POINTER TO ENTRY IF FOUND !USES GLOBALS ENTRY AND FLAG !IF FLAG IS SET TPREV POINTS TO !PREVIOUS ENTRY ON LIST IF ANY. ZERO IF NONE T_ABS(.(ENTRY+2) XOR .(ENTRY+1)) MOD EHSIZ; EHASHP_EHASH[.T]<0,0>; IF .EHASH[.T] EQL 0 THEN BEGIN FLAG_0; TPREV_EHASH[.T]<0,0>; NEDCOR_1; RETURN(.TPREV); END ELSE P_.EHASH[.T]; TPREV_.P; NEDCOR_0; LOKER: DO BEGIN IF .P[EMPTY] THEN LEAVE LOKER; PC_.P+1; IF @.PC EQL .(ENTRY+1) THEN BEGIN PC_.PC+1; IF @.PC EQL .(ENTRY+2) THEN BEGIN PC_.PC+1; IF @.PC EQL .(ENTRY+3) THEN BEGIN FLAG_1; RETURN(.P); END; END; END; TPREV_.P; P_.P[CLINK]; END UNTIL .P EQL 0; !EQL 0 FLAG_0; IF .P EQL 0 THEN NEDCOR_1; RETURN(.TPREV); END; OWN THISBLK,MOREFLG; GLOBAL ROUTINE MAKETRY (PLACE,CNODE,SHAPE)= BEGIN EXTERNAL LOOPNO; OWN PHAZ2 ENTRYP; MAP PEXPRNODE CNODE; MAP PHAZ2 PLACE; !ENTERS AN ENTRY INTO HASH TABLE !PLACE POINTS TO WHERE IT GOES !ZERO MEANS WE NEED CORE FOR IT ENTRYP_ENTRY<0,0>; IF .NEDCOR THEN BEGIN NAME_6; PLACE_CORMAN(); TPREV[CLINK]_.PLACE; END ELSE !IT IS POSSIBLE THAT PLACE POINTS TO A FULL ENTRY WHICH !POINTS TO AN EMPTY ENTRY. OBVIOUSLY, IT IS THE EMPTY !ENTRY THAT WE DESIRE TO USE. IF NOT .PLACE[EMPTY] THEN PLACE_.PLACE[CLINK]; PLACE[USECNT]_1; PLACE[EMPTY]_0; PLACE[CMNFLGS]_0; PLACE[TEMPER]_0; PLACE[BLKID]_.ENTRYP[BLKID]; PLACE[HOP]_.ENTRYP[HOP]; PLACE[HA1]_.ENTRYP[HA1]; PLACE[HA2]_.ENTRYP[HA2]; PLACE[HDEF1]_.ENTRYP[HDEF1]; PLACE[HDEF2]_.ENTRYP[HDEF2]; PLACE[LKER]_.CNODE; !IF THIS IS AN ARRAYREF ZERO THE PARENT(LINK) FIELD IF .CNODE[OPRCLS] EQL ARRAYREF THEN CNODE[PARENT]_0; !THE SPECIAL CASE FOR LOCAL COMMON SUB-EXPRESSIONS OF A !SINGLE VARIABLE AS A SUBSCRIPT OF UNDER A RELATIONAL !SET TEMPER TO THE MODULE OWN VARHOLDER FOR LATER USE !IN UNRYMATCHER. !THIS IS THE ONLY PLACE WHERE A DATAOPR SHOULD OCCUR. IF .CNODE[OPRCLS] EQL DATAOPR THEN PLACE[TEMPER]_.VARHOLDER ELSE !LOOK TO SEE IF THIS ONE CONTAINS ANOTHER ONE. CHKHAIR(.CNODE,.PLACE,.SHAPE); .PLACE END; EXTERNAL PREV; MAP PHAZ2 P:QQ:P1:PO:PREV; GLOBAL ROUTINE DELETE(NOD,NUMB)= BEGIN EXTERNAL PUTBACKARRAY; !**;[442], DELETE @5374, DCE, 9-SEP-76 LOCAL TSAVE; ![442] LOCAL T; MAP PHAZ2 NOD; !**;[442], DELETE @5376, DCE, 9-SEP-76 !**;[442], MAKE THE COMMENT REFLECT REALITY !TPREV POINTS TO PREVIOUS NODE OR NODE ITSELF INITIALLY [442] !DEPENDING ON IF THIS IS THE FIRST NODE IN ITS HASH LIST [442] !NOD POINTS TO ENTRY IN HASH TABLE !LINK TO BEGINNING OF EMPTY LIST !THE TEMP T IS NECESSARY TO INSURE A CORRECT NEGATIVE VALUE LABEL ENDLOK; T_.NOD[USECNT]-.NUMB; !IF IS BECAME UNUSED IF .T LEQ 0 THEN BEGIN NOD[EMPTY]_1; NOD[USECNT]_0; !IF OPTIMIZING WE MAY HAVE TO RECONSTRUCT AN !AN ARRAYREF NODE IF .FLGREG THEN PUTBACKARRAY(.NOD,(IF .NOD[NBRCH] THEN SKEW ELSE STGHT)); PREV_.NOD[CLINK]; !PREV IS A TEMP IF .PREV EQL 0 THEN RETURN; IF .PREV[EMPTY] THEN RETURN; !LINK OUT ENTRY THAT BECAME EMPTY AND PUT IT AT !THE END OF THE LIST. !NOTE THAT TPREV WAS SET BY TBLSRCH TO POINT !TO THE ENTRY BEFORE NOD. !**;[442], DELETE @5404, DCE, 9-SEP-76 TSAVE_TPREV[CLINK]_.PREV;![442] ENDLOK: WHILE 1 DO !LOOK FOR END OF LIST BEGIN TPREV_.PREV; PREV_.PREV[CLINK]; IF .PREV EQL 0 THEN BEGIN TPREV[CLINK]_.NOD; NOD[CLINK]_0; LEAVE ENDLOK; END ELSE IF .PREV[EMPTY] THEN BEGIN NOD[CLINK]_.PREV; TPREV[CLINK]_.NOD; LEAVE ENDLOK; END; END; IF @.EHASHP EQL .NOD THEN !**;[442], DELETE @5425, DCE, 9-SEP-76 !**;[442], MAKE THE HASH POINTER CORRECTLY POINT TO !**;[442], THE NEW FIRST ELEMENT IN THE LINKED LIST !+;;*[442], IN THE CASE THE DELETED ELEMENT WAS FIRST %[442]% EHASH[.EHASHP-EHASH<0,0>]_.TSAVE; END !ENTRY GOING EMPTY ELSE !PUT NEW COUNT INTO NODE NOD[USECNT]_.T; END; !HASH NODE ! ! ----------------------------------- ! * * * ! * USECNT * CLINK * ! * * * ! ----------------------------------- ! * * * ! * BLKID * HOP * ! * * * ! ----------------------------------- ! * * * ! * HA1 * HA2 * ! * * * ! ----------------------------------- ! * * * ! * HDEF1 * HDEF2 * ! * * * !------------------------------------ ! * * * ! * TEMPER * LKER * ! * * * ! ----------------------------------- ! * * * ! * NBRCH * STPT * ! * * * ! ----------------------------------- ! FIRST BIT OF BLKID IS 1 IF BLOCK DELETED ! !********************************** ! ROUTINE LOCLMOV(CNODE)= BEGIN !CALLED ONLY IN THE LOCAL COMMON SUB-EXPRESSION ELIMINATION !CASE. TEMPER IN THIS CASE POINTS TO A COMMON SUB- !**EXPRESSION NODE**. A LINKED LIST OF SUCH IS MADE AT !LOCLNK, BACKST POINTS TO THE TOP OF THE LIST. MAP BASE CNODE; MAP BASE LOCLNK:BACKST; IF .LOCLNK EQL 0 THEN BEGIN LOCLNK_.CNODE; BACKST[SRCLINK]_.CNODE; END ELSE BEGIN LOCLNK[SRCLINK]_.CNODE; CNODE[SRCLINK]_0; LOCLNK_.CNODE; END; END; ! ! ! ROUTINE ARGCMN(ANODE,LG)= BEGIN !LG IS LOCAL - GLOBAL SWITCH. !ANODE SHOULD BE EITHER A POINTER TO A CMNSUB NODE (LOCAL) !OR AN OPTIMIZER CREATED VARIABLE STARTING WITH .O (GLOBAL) !THE ROUTINE RETURNS 1 IF EITHER OF THESE CONDITIONS IS TRUE. !IF IT IS RETURNING A ONE THE GLOBAL QQ ALSO CONTAINS THE %[V5]% !OMOVDCNS & USECNT FIELDS OF THE SYMBOL TABLE ENTRY EXTERNAL QQ; MAP BASE ANODE:T; IF .LG THEN BEGIN IF OPTMP(ANODE) THEN BEGIN %[V5]% QQ _ .ANODE [EXPRUSE]; %[V5]% QQ _ .ANODE [OMOVDCNS]; RETURN(1); END ELSE RETURN(0) END ELSE !LG=0(LOCAL) BEGIN IF .ANODE[OPRCLS] EQL CMNSUB THEN BEGIN QQ_.ANODE[EXPRUSE]; RETURN(1); END ELSE RETURN(0); END; END; ROUTINE LOK1SUBS(CNODE,LG)= BEGIN !DETERMINE IF ARG1 OF CNODE IS A : ! CMNSUB NODE (IF LG=0) ! A .O TEMP (IF LG=1) !THIS IS THE CONTROLLING CASE. THE REAL WORK IS DONE BY ARGCMN. !THIS ROUTINE RETURNS THE LOGICAL VALUE RETURNED TO IT BY !ARGCMN. MAP PEXPRNODE CNODE; RETURN( CASE .CNODE[OPRCLS] OF SET ARGCMN(.CNODE[ARG1PTR],.LG); !BOOLEAN 0; !DATAOPR ARGCMN(.CNODE[ARG1PTR],.LG); !RELATIONAL 0; !FNCALL ARGCMN(.CNODE[ARG1PTR],.LG); !ARITHMETIC 0; !TYPECNV 0; !ARRAYREF 0; !CMNSUB 0; !NEGNOT ARGCMN(.CNODE[ARG1PTR],.LG); !SPECOP 0; !FIELDREF 0; !STORCLS 0; !REGCONTENTS 0; !LABOP 0; !STATEMENT 0; !IOLCLS ARGCMN(.CNODE[ARG1PTR],.LG) !INLINFN TES); END; ROUTINE LOK2SUBS(CNODE,LG)= BEGIN !FUNCTIONS EXACTLY THE SAME AS LOK1SUBS, EXCEPT ON !ARG2 OF CNODE. MAP BASE CNODE; RETURN( CASE .CNODE[OPRCLS] OF SET ARGCMN(.CNODE[ARG2PTR],.LG); !BOOLEAN 0; !DATAOPR ARGCMN(.CNODE[ARG2PTR],.LG); !RELATIONAL 0; !FNCALL ARGCMN(.CNODE[ARG2PTR],.LG); !ARITHMETIC ARGCMN(.CNODE[ARG2PTR],.LG); !TYPECNV 0; !ARRAYREF 0; !CMNSUB ARGCMN(.CNODE[ARG2PTR],.LG); !NEGNOT 0; !SPECOP 0; !FIELDREF 0; !STORCLS 0; !REGCONTENTS 0; !LABOP 0; !STATEMENT 0; !IOLCLS BEGIN !INLINFN IF .CNODE[ARG2PTR] NEQ 0 THEN ARGCMN(.CNODE[ARG2PTR],.LG) END TES); END; ROUTINE DELLNK(CNODE)= BEGIN !REMOVE COMMON SUB-EXPRESSION CNODE FROM THE LINKED LISTOF !SAME HEADED BY BACKST. EXTERNAL BACKST; MAP BASE BACKST:PREV:P1:CNODE; !INITIALIZE THINGS PREV_.BACKST; P1_.BACKST[SRCLINK]; !LOOK THROUGH THE LIST WHILE .P1 NEQ 0 DO BEGIN IF .P1 EQL .CNODE THEN BEGIN PREV[SRCLINK]_.CNODE[SRCLINK]; RETURN; END; PREV_.P1; P1_.P1[SRCLINK]; END; END; ROUTINE LOCLDEPD= BEGIN !EXAMINE LINKED LIST OF COMMON SUB-EXPRESSIONS. BACKST !IS THE HEAD OF THE LIST. EXPRESSIONS ARE ORDERED !FROM THE BOTTOM - UP IN THE TREE SENSE. !THIS IS THE CONTROLLING ROUTINE FOR THE GENERAL PROCESS: ! DETERMINE IF EACH EXPRESSION HAS OTHER COMMON-SUBS UBDER IT ! IF SO, LOOK THESE UP IN THE HASH TABLE. ! IF THE USE COUNT OF THE SUBORDINATE = THE USECNT OF ! THE PARENT, THEN REMOVE THE LITTLE ONE, AND ITS ! COMMON SUB-EXPRESSION NODE. OWN PEXPRNODE EXPR; MAP BASE T:PAE; EXTERNAL BACKST; MAP BASE BACKST; EXPR_.BACKST[SRCLINK]; !FOR EACH EXPRESSION ON THE LIST WHILE .EXPR NEQ 0 DO BEGIN IF .EXPR[A2VALFLG] THEN HASHIT(.EXPR[ARG2PTR],UNARY) ELSE HASHIT(.EXPR[ARG2PTR],STGHT); !LOOK UP THE EXPRESSION IN THE HASH TABLE PHI_TBLSRCH(); !IF THERE ARE COMMON SUBS UNDER IT IF .PHI[CMNUNDER] THEN BEGIN !LOOK AT EACH ARG OF THE EXPRESSION. !FIRST LOOK AT REAL EXPRESSION PAE_.EXPR[ARG2PTR]; !LOK1SUBS AND LOK2SUBS RETURN 1 IF WE ARE !INTERESTED IN THIS ONE AND THE USE COUNT IN THE !GLOBAL QQ IF LOK1SUBS(.PAE,0) THEN IF .QQ EQL .PHI[USECNT] THEN BEGIN T_.PAE[ARG1PTR]; PAE[ARG1PTR]_.T[ARG2PTR]; !RESET VALFLGS PAE[A1VALFLG]_0; DELLNK(.T); !ALSO FIX PARENT T_.PAE[ARG1PTR]; T[PARENT]_.PAE; END; IF LOK2SUBS(.PAE,0) THEN IF .QQ EQL .PHI[USECNT] THEN BEGIN T_.PAE[ARG2PTR]; PAE[ARG2PTR]_.T[ARG2PTR]; !RESET VALFLG PAE[A2VALFLG]_0; DELLNK(.T); !FIX PARENT TOO T_.PAE[ARG2PTR]; T[PARENT]_.PAE; END; END; EXPR_.EXPR[SRCLINK]; END; !WHILE !CLEANUP THE EXPRESSION NODES THAT HAVE EXPRUSE LEFT IN THEM EXPR_.BACKST[SRCLINK]; WHILE .EXPR NEQ 0 DO BEGIN EXPR[EXPRUSE]_0; EXPR_.EXPR[SRCLINK]; END; !ALSO GO THRU THE HASH TABLE AND MARK THE ENTRIES EMPTY SLINGHASH(); END; END ELUDOM