INCLUDE  "ERCC07.TRIMP_TFORM1S"
      INCLUDE  "ERCC07.TRIPCNSTS"
EXTRINSICRECORD (WORKAF) WORKA
EXTRINSICRECORD (PARMF) PARM
CONSTINTEGER  YES=1
CONSTINTEGER  NO=0
EXTERNALROUTINESPEC  IMPABORT
EXTERNALROUTINESPEC  FAULT(INTEGER  N,DATA,IDENT)
EXTERNALROUTINESPEC  PRINT TRIPS(RECORD (TRIPF) ARRAYNAME  TRIPLES)
CONSTBYTEINTEGERARRAY  WORDS(0:7)=0(3),1,1,2,4,8; 
ROUTINE  EXTRACT(RECORD (RD) NAME  OPND, LONGINTEGERNAME  VAL,
    LONGLONGREALNAME  RVAL, STRINGNAME  STRVAL)
!***********************************************************************
!*    EXTRACTS A CONTANT OPERAND RETURNING REAL &INT VALUES           *
!***********************************************************************
INTEGER  TYPE,PREC,I,AD
      TYPE=OPND_PTYPE; PREC=TYPE>>4
      TYPE=TYPE&15
      IF  TYPE=5 START 
         LENGTH(STRVAL)=WORKA_A(OPND_D)
         FOR  I=1,1,OPND_XTRA CYCLE 
            CHARNO(STRVAL,I)=WORKA_A(OPND_D+I)
         REPEAT 
      FINISHELSEIF  TYPE=1 THENSTART 
         IF  PREC=6 THEN  VAL=OPND_LI ELSE  VAL=OPND_D
         RVAL=VAL
      FINISHELSESTART 
         VAL=0
         IF  PREC=7 START 
            FOR  I=0,1,15 CYCLE 
               BYTEINTEGER(ADDR(RVAL)+I)=WORKA_A(OPND_XTRA+I)
            REPEAT 
         FINISH  ELSE  IF  PREC=5 THEN  RVAL=OPND_R ELSE  RVAL=OPND_LR
      FINISH 
END 
EXTERNALROUTINE  CTOP(INTEGERNAME  FLAG,MASK, INTEGER  XTRA,
    RECORD (RD) NAME  OPND1,OPND2)
!***********************************************************************
!*    AN OPERATION HAS BEEN FOUND WHERE BOTH OPERANDS ARE              *
!*    CONSTANTS OR KNOWN AT COMPILE TIME. THIS ROUTINE INTERPRETS      *
!*    THE OPERATION                                                    *
!*    ON EXIT FLAG=0 IF INTERPRETED. REFRAINS FROM INTERPRETING        *
!*    X=1/0 FOR EXAMPLE. CODE IS PLANTED FOR THESE FUNNIES             *
!***********************************************************************
CONSTINTEGER  UTRUNCMASK=X'00000800',BTRUNCMASK=X'00000013'
CONSTBYTEINTEGERARRAY  FCOMP(1:14)= C 
                                        8,10,2,7,12,4,7,
                                        8,12,4,7,10,2,7

INTEGER  K,TYPEP,PRECP,OP,VAL,SVAL1,SVAL2,C,D,JJ,KK,TRUNCMASK
STRING (255) STRVAL1,STRVAL2
LONGINTEGER  VAL1,VAL2
LONGLONGREAL  RVAL1,RVAL2
SWITCH  UISW,URSW(10:40),BISW,BRSW(0:24)
      ONEVENT  1,2 START 
         RETURN 
      FINISH 
      TYPEP=OPND1_PTYPE&7; PRECP=OPND1_PTYPE>>4&15; OP=FLAG
      EXTRACT(OPND1,VAL1,RVAL1,STRVAL1)
      SVAL1<-VAL1
      IF  OP<128 START ;                ! UNARY
         RETURNUNLESS  10<=OP<=40
         TRUNCMASK=UTRUNCMASK
         IF  TYPEP=2 THEN  ->URSW(OP) ELSE  ->UISW(OP)
      FINISH 
      OP=OP-128
      RETURNIF  OP>24
      EXTRACT(OPND2,VAL2,RVAL2,STRVAL2)
      SVAL2<-VAL2
      IF  TYPEP=2 THEN  ->BRSW(OP) ELSE  ->BISW(OP)
UISW(10):                               ! ¬
      VAL1=¬VAL1
INTEND:
      IF  PRECP=6 THEN  START 
         OPND1_LI=VAL1
         FLAG=0
      FINISH  ELSE  START 
         VAL<-VAL1
         IF  VAL=VAL1 OR  1<<OP&TRUNCMASK=0 THEN  FLAG=0 AND  OPND1_D=VAL
                                       ! NO ARITH OFLOW CONDITION
      FINISH 
      IF  FLAG=0 START 
         OPND1_PTYPE=PRECP<<4!1
         IF  X'FFFF8000'<=VAL1<=X'FFFF' THEN  OPND1_FLAG=0 ELSE  OPND1_FLAG=1
      FINISH 
      RETURN 
UISW(11):                               ! INTEGER NEGATE
      VAL1=-VAL1; ->INT END
UISW(13):                               ! INTEGER ABS
      VAL1=IMOD(VAL1); ->INT END
UISW(12):                               ! INTEGER FLOAT
      RVAL1=VAL1; PRECP=PRECP+1
      ->REAL END
URSW(15):                               ! STRETCH REAL
      PRECP=PRECP+1
REAL END:OPND1_FLAG=1
      IF  PRECP=5 THEN  OPND1_R=RVAL1 ELSE  OPND1_LR=RVAL1
!      %IF PRECP=7 %THEN %START
!         OPND1_FLAG=3
!         OPND1_XTRA=ADDR(A(R))
!         %CYCLE K=0,1,15
!            A(R)=BYTEINTEGER(ADDR(RVAL1)+K)
!            R=R+1
!         %REPEAT
!      %FINISH
      FLAG=0; OPND1_PTYPE=16*PRECP+2
      RETURN 
UISW(15):                               ! STRETCH INTEGER
      PRECP=PRECP+1; ->INT END
UISW(14):                               ! SHORTEN INTEGER
      IF  PRECP=6 THEN  PRECP=5 AND  ->INT END
      IF  IMOD(VAL1)<=X'7FFF' THEN  PRECP=4 AND  ->INT END
      RETURN 
URSW(14):                               ! SHORTEN REAL
      PRECP=PRECP-1
      ->REAL END
URSW(12):                               ! FLOAT REAL
      IMPABORT
UISW(16):                               ! SHORTEN FOR <-
      IF  PRECP=5 THEN  VAL1=VAL1&X'FFFF' AND  PRECP=4 AND  ->INTEND
      RETURN 
URSW(36):                               ! INT
      RETURNUNLESS  MOD(RVAL1)<X'7FFFFFFE'
      VAL1=INT(RVAL1)
      PRECP=5
      ->INTEND
URSW(37):                               ! INTPT
      RETURNUNLESS  MOD(RVAL1)<X'7FFFFFFE'
      VAL1=INTPT(RVAL1)
      PRECP=5
      ->INTEND
UISW(38):                               ! TOSTRING
      STRVAL1=TOSTRING(VAL1)
      ->STREND
BISW(0):                                ! ADD
BISW(14):                               ! COMBINE VMY RESULTS
      VAL1=VAL1+VAL2; ->INT END
BISW(1):                                ! MINUS
      VAL1=VAL1-VAL2; ->INT END
BISW(2):                                ! EXCLUSIVE OR
      VAL1=VAL1!!VAL2; ->INT END
BISW(3):                                ! OR
      VAL1=VAL1!VAL2; ->INT END
BISW(4):                                ! MULT
      VAL1=VAL1*VAL2; ->INT END
BISW(6):RETURN ;                        ! / DIVISION
BISW(5):RETURNIF  VAL2=0;               ! // DIVISION
      VAL1=VAL1//VAL2; ->INT END
BISW(7):                                ! AND
      VAL1=VAL1&VAL2; ->INT END
BISW(9):                                ! SLL
      IF  PRECP=6 THEN  VAL1=VAL1<<SVAL2 ELSE  VAL1=SVAL1<<SVAL2
      ->INT END
BISW(8):                                ! SRL
      IF  PRECP=6 THEN  VAL1=VAL1>>SVAL2 ELSE  VAL1=SVAL1>>SVAL2
      ->INT END
BISW(13):                               ! VMY & CHK BOUNDS
      C=VAL2>>24;                       ! DIMENSION
      D=VAL2>>16&31;                    ! TOTAL NO OF DIMENS
      C=3*(D+1-C);                      ! TRIPLE OFFSET FROM DVBASE
      D=VAL2&X'FFFF';                   ! DV POINTER
      RETURNUNLESS  D>0;                ! UNLESS DV AVAILABLE
      JJ=(VAL1-WORKA_CTABLE(D+C))*WORKA_CTABLE(D+C+1)
      IF  JJ<0 OR  JJ>WORKA_CTABLE(D+C+2) THEN  C 
         FAULT(50,VAL1,XTRA&X'FFFF')
      VAL1=JJ
      ->INT END
BISW(18):                               ! ARRAY SCALE
      D=VAL2>>16&31;                    ! TOTAL NO OF DIMENSIONS
      KK=VAL2&X'FFFF';                  ! DV DISP
      RETURNUNLESS  KK>0
!      JJ=WORKA_CTABLE(KK+4);            ! LB(1)
!      C=6
!      %WHILE C<=3*D %CYCLE
!         JJ=JJ+WORKA_CTABLE(KK+C-1)*WORKA_CTABLE(KK+C+1)
!         C=C+3
!      %REPEAT
!      VAL1=VAL1-JJ
      ->INT END
BISW(11):
BISW(12):                               ! COMPARISONS
BRSW(11):
BRSW(12):                               ! REAL COMPARISONS
      MASK=FCOMP(XTRA)
      FLAG=0
      IF  TYPEP=2 THEN  ->RCOMP
      IF (MASK&8#0 AND  VAL1=VAL2) OR (MASK&4#0 AND  VAL1<VAL2) OR  C 
         (MASK&2#0 AND  VAL1>VAL2) THEN  MASK=15 ELSE  MASK=0
      RETURN 
RCOMP:
      IF (MASK&8#0 AND  RVAL1=RVAL2) OR (MASK&4#0 AND  RVAL1<RVAL2) OR  C 
         (MASK&2#0 AND  RVAL1>RVAL2) THEN  MASK=15 ELSE  MASK=0
      RETURN 
URSW(11):                               ! NEGATE
      RVAL1=-RVAL1; ->REAL END
BRSW(13):                               ! ABS
      RVAL1=MOD(RVAL1); ->REAL END
BRSW(0):                                ! ADD
      RVAL1=RVAL1+RVAL2; ->REAL END
BRSW(1):                                ! SUBTRACT
      RVAL1=RVAL1-RVAL2; ->REAL END
BRSW(4):                                ! MULT
      RVAL1=RVAL1*RVAL2; ->REAL END
BRSW(6):                                ! DIVISION
      RETURNIF  RVAL2=0;                ! AVOID DIV BY ZERO
      RVAL1=RVAL1/RVAL2; ->REAL END
BISW(10):                               ! '**' WITH 2 INTEGER OPERANDS
BRSW(10):                               ! '**' WITH AT LEAST 1 REAL
      RETURNUNLESS  OPND2_PTYPE&7=1 AND -63<=VAL2<=63
      RVAL1=RVAL1**VAL2
      ->REALEND
BISW(17):                               ! '****' WITH 2 INTEGER OPERAND
      RETURNUNLESS  0<=VAL2<=63
      VAL2=1
      WHILE  SVAL2>0 CYCLE 
         VAL2=VAL2*VAL1
         SVAL2=SVAL2-1
!         %RETURN %IF VAL2#INTEGER(ADDR(VAL2)+4)
      REPEAT 
      VAL1=VAL2; ->INT END
BISW(24):                               ! CONCAT
      RETURNIF  LENGTH(STRVAL1)+LENGTH(STRVAL2)>255
      STRVAL1=STRVAL1.STRVAL2
STREND:                                 ! RETURN VALUE
      OPND1_PTYPE=X'35'
      OPND1_FLAG=LCONST
      OPND1_XTRA=LENGTH(STRVAL1)
      JJ=WORKA_ARTOP
      WORKA_A(JJ)=OPND1_XTRA
      FOR  K=1,1,OPND1_XTRA CYCLE 
         WORKA_A(JJ+K)=CHARNO(STRVAL1,K)
      REPEAT 
      OPND1_D=JJ
      WORKA_ARTOP=(JJ+OPND1_XTRA+2)&(-2); ! PERQ KEEP 16 BIT ALIGNED
      FLAG=0
      RETURN 
URSW(*):
UISW(*):
BRSW(*):
BISW(*):
END 
EXTERNALROUTINE  FLAG AND FOLD(RECORD (TRIPF) ARRAYNAME  TRIPLES)
!***********************************************************************
!*    WORKS DOWN AN ARRAY OF TRIPLES SETTING BITS FOR CODE GENERATOR   *
!*    ALSO FOLDS OUT ANY REMAINING CONSTANT OPERATIONS                 *
!***********************************************************************
INTEGER  STPTR,CURRTRIPNO,I,J,DEPTH
CONSTINTEGER  FOLDI=X'1C00007F';        ! FOLD 10-16 & 36-38
CONSTINTEGER  FOLDR=X'0107FFFF';        ! FOLD 128-146 &152
RECORD (TRIPF) NAME  CURRT,REFT
ROUTINESPEC  INSPECT OPND(INTEGER  NO)
ROUTINESPEC  REPLACE TRIPREF(INTEGER  TRIP, RECORD (RD) NAME  OPND)
      STPTR=TRIPLES(0)_FLINK
      DEPTH=0
!
      WHILE  STPTR>0 CYCLE 
         CURRT==TRIPLES(STPTR)
         CURRTRIPNO=STPTR
         STPTR=CURRT_FLINK
         INSPECT OPND(1)
         IF  CURRT_OPERN>=128 THEN  INSPECT OPND(2)
!
         IF  CURRT_FLAGS&CONSTANTOP#0 AND ((CURRT_OPERN<128 AND  C 
            FOLDI&1<<(CURRT_OPERN-10)#0) OR (CURRT_OPND1_FLAG<=1 AND  C 
            CURRT_OPND2_FLAG<=1 AND  FOLDR&1<<(CURRT_OPERN&31)#0)) START 
            I=CURRT_OPERN
            CTOP(I,J,CURRT_X1,CURRT_OPND1,CURRT_OPND2)
            IF  I=0 THENSTART 
               CURRT_X1=CURRT_OPERN;    ! FOR DEBUGGING OPTIMISATIONS
               CURRT_OPERN=NULLT
               REPLACE TRIPREF(CURR TRIPNO,CURRT_OPND1)
            FINISH 
         FINISH 
         IF  CURRT_OPERN=LASS AND  CURRT_FLAGS&CONSTANTOP#0 AND  C 
            CURRT_CNT>0 THEN  REPLACE TRIPREF(CURRTRIPNO,CURRT_OPND2)
         CURRT_DPTH<-DEPTH
         IF  CURRT_CNT>0 THEN  DEPTH=DEPTH+WORDS(CURRT_OPTYPE>>4)
      REPEAT 
      RETURN 
ROUTINE  INSPECT OPND(INTEGER  NO)
RECORD (TRIPF) NAME  RTRIP
RECORD (RD) NAME  OPND
CONSTBYTEINTEGERARRAY  LOAD ALLOW(0:199)=LOAD OP1(128){UNARY},
                                        LOADOP1!LOADOP2(10),
                                        LOADOP1{**},
                                        LOADOP1!LOADOP2(2),
                                        LOADOP1{VMY},
                                        LOADOP1!LOADOP2,
                                        0(2){ASS AND JAM ASS},
                                        LOADOP1{****},
                                        LOADOP1{SCALE},
                                        LOADOP1!LOADOP2,
                                        LOADOP2{INDEXED FETCH},
                                        LOADOP2{LASS},
                                        LOADOP1!LOADOP2(4),
                                        LOADOP2(5){P PASSING},
                                        LOADOP1!LOADOP2(8),
                                        LOADOP2(7){STR,PTR&RESULT ASSMNT},
                                        LOADOP1!LOADOP2(7),
                                        LOADOP2{REC ASSNMNT},
                                        LOADOP1!LOADOP2(*);
INTEGER  I,LOADOP
      OPND==CURRT_OPND1
      LOADOP=LOAD OP1
      IF  NO=2 THEN  OPND==CURRT_OPND2 AND  LOADOP=LOAD OP2
      LOADOP=LOADOP&LOAD ALLOW(CURRT_OPERN)
      IF  OPND_FLAG<=1 THEN  CURRT_FLAGS=CURRT_FLAGS!CONSTANTOP
      IF  OPND_FLAG<8 THEN  CURRT_FLAGS=CURRT_FLAGS!LOADOP
      IF  OPND_FLAG=REFTRIP START 
         RTRIP==TRIPLES(OPND_D)
         IF  RTRIP_PUSE#CURRTRIPNO OR  RTRIP_OPERN=LASS OR  C 
            RTRIP_OPERN=PRECC OR  RTRIP_OPERN=CONCAT OR  C 
            RTRIP_OPERN=ITOS1 THEN  CURRT_FLAGS=CURRT_FLAGS!LOADOP
         IF  RTRIP_PUSE=CURRTRIPNO THEN  DEPTH=DEPTH-WORDS(RTRIP_OPTYPE>>4)
      FINISH 
END 
ROUTINE  REPLACE TRIPREF(INTEGER  TRIP, RECORD (RD) NAME  OPND)
INTEGER  PTR
BYTEINTEGERNAME  COUNT
RECORD (TRIPF) NAME  RTRIP
      PTR=STPTR
      COUNT==TRIPLES(TRIP)_CNT
      WHILE  COUNT>0 AND  PTR>0 CYCLE 
         RTRIP==TRIPLES(PTR)
         PTR=RTRIP_FLINK
         IF  RTRIP_OPND1_FLAG=REFTRIP AND  RTRIP_OPND1_D=TRIP START 
            RTRIP_OPND1=OPND
            COUNT=COUNT-1
         FINISH 
         IF  RTRIP_OPERN>=128 AND  RTRIP_OPND2_FLAG=REFTRIP AND  C 
            RTRIP_OPND2_D=TRIP START 
            RTRIP_OPND2=OPND
            COUNT=COUNT-1
         FINISH 
      REPEAT 
END 
END 
EXTERNALROUTINE  TRIP OPT(RECORD (TRIPF) ARRAYNAME  TRIPLES,
    INTEGERNAME  NEXT TRIP)
!***********************************************************************
!*    SCANS A TRIPLES LIST FOR POSSIBLE OPTIMISATIONS
!***********************************************************************
INTEGER  CHANGES,DUPS,DUPTNO,PTR,I,J,K,VAL,CURR,NEXT,OP1,OP2,CTOPOP
BYTEINTEGERARRAYNAME  A
RECORD (TRIPF) NAME  CURRT,NEWT,NEXTT
RECORD (RD) NAME  OPND1,OPND2
RECORD (LISTF) NAME  LCELL
INTEGERFNSPEC  PRELOAD PLACE(INTEGER  TRIP)
ROUTINESPEC  NOOP(INTEGER  TRIPLE, RECORD (RD) NAME  ROPND)

INTEGERFNSPEC  SAME OPND(RECORD (RD) NAME  OPND1,OPND2)
ROUTINESPEC  CHECK DUPS(INTEGER  STRIPNO,STRIPNO)
ROUTINESPEC  DUPLICATE TRIP(INTEGER  TRIPNO,DTRIPNO)
ROUTINESPEC  DEC USE(INTEGER  TRIPLE NO)
ROUTINESPEC  DELETE TRIPLE(INTEGER  TRIPLE NO)
CONSTBYTEINTEGERARRAY  FOLD NOOP INFO(0:199)= 0(128),
                    X'81',X'41',X'81',X'81',X'86',{+,-,!!,!,*} C 
                    2,0,X'84',1,1,{//,/,&,>>,<<} C 
                    2,0,0,3,X'81',{**,COMP,DCOMP,VMY,COMB} C 
                    0,0,2,0,1,{=,<-,****,SCALE,INDEX} C 
                    0{IFETCH},0(*)

! 2**0 SET IF SECOND OPERANR ZERO IS NOOP
! 2**1 SET IF SECOND OPERAND 1 IS A NOOP
! 2**2 SET IF SECOND OPERAND 0 MEANS RESULT=0
! 2**5 SET IF SOME FOLDING POSSIBLE
! 2**6 SET IF FOLDING WITH ITSELF POSSIBLE BUT NOT SIMPE
! 2**7 SET FOR NORMAL FOLDING
!
      CHANGES=0;                        ! NO CHANGES AS YET
      DUPS=0;                           ! NO DUPLICATES YET

      FLAG AND FOLD(TRIPLES)
      A==WORKA_A
!
! FIRST OPTIMISATIO IS TO SEARCH FOR AND REMOVE NOPS
! LIKE *1 OR <<0 OR +0 ETC. THESE ARE SURPRISINGLY COMMON
! IN PROGRAMS MADE MACHINE INDEPENDENT BY LIBERAL USE
! OF CONSTANT VARIABLES
!
      PTR=TRIPLES(0)_FLINK
      WHILE  PTR>0 CYCLE 
         CURRT==TRIPLES(PTR);           ! EXAMINE EACH TRIPLE
         CURR=PTR
         PTR=CURRT_FLINK
         CONTINUEIF  CURRT_FLAGS&DONT OPT#0
         I=CURRT_OPERN
         OPND1==CURRT_OPND1
         OPND2==CURRT_OPND2
         IF  I>=128 THENSTART ;         ! BINARY OPERATIONS
            J=FOLD NOOP INFO(I)&15
            CONTINUEUNLESS  OPND2_FLAG<=1 AND  J#0 AND  OPND2_PTYPE&7=1
            VAL=OPND2_D;                ! VALUE OF CONSTANT
            IF (J&1#0 AND  VAL=0) OR (J&2#0 AND  VAL=1) START 
               NOOP(CURR,OPND1);        ! THIS IS NOOP
               CONTINUE 
            FINISH 
            IF  J&4#0 AND  VAL=0 THENSTART 
               IF  OPND1_FLAG=REFTRIP THEN  DEC USE(OPND1_D)
               CURRT_OPND1=OPND2;       ! RESULT IS ZERO
               NOOP(CURR,OPND2)
                                        ! MAY CAUSE OTHER NOOPS
                                        ! GE I=(A+B)*0
            FINISH 
         FINISHELSESTART ;              ! UNARY
                                        ! OPTIMISE LOAD DOUBLE & SHRINK
                                        ! IN CASE WHERE CHECKING IS OFF
            CONTINUEUNLESS  OPND1_PTYPE=X'51' AND (I=JAMSHRTN OR  C 
               (I=SHRTN AND  PARM_OPT=0))
            IF  OPND1_FLAG=2 AND  A(OPND1_D+2)=2=A(OPND2_D+3) THENSTART 
               J=WORKA_TAGS(OPND1_XTRA)
               LCELL==RECORD(WORKA_AASL0+16*J); ! ON TO NAME RECORD
               OPND1_FLAG=7;            ! LOCAL
               OPND1_PTYPE=X'41';       ! PRESHORTENED
               CURRT_OPTYPE=X'41';      ! REVISE TRIPLE PTYPE
               OPND1_D=(LCELL_UIOJ&X'F0')<<12!LCELL_SLINK
               NOOP(CURR,OPND1)
            FINISH 
            IF  OPND1_FLAG=REFTRIP THENSTART 
               NEXTT==TRIPLES(OPND1_D)
               IF  NEXTT_CNT=1 AND  NEXTT_OPERN=IFETCH START 
                  NEXTT_OPND1_PTYPE=X'41'
                  NEXTT_OPTYPE=X'41'
                  OPND1_PTYPE=X'41'
                  NOOP(CURR,OPND1)
               FINISH 
            FINISH 
         FINISH 
      REPEAT 
!
! ADVANCED FOLDING FACTOR CONSTANTS OUT OF 2 OR MORE TRIPLES
! TO SAVE AN OPERATION. ONLY MORE USUSAL CASE CATERED FOR AS IN
! VAR+CONST+CONST.
!
      PTR=TRIPLES(0)_FLINK
      WHILE  PTR>0 CYCLE 
         CURRT==TRIPLES(PTR)
         NEXT=CURRT_FLINK
         EXITIF  NEXT<=0
         NEXTT==TRIPLES(NEXT)
         UNLESS  CURRT_CNT=1 AND  NEXTT_CNT=1 AND  C 
            CURRT_FLAGS&NEXTT_FLAGS&CONSTANTOP#0 AND  CURRT_PUSE=NEXT THEN  C 
            PTR=NEXT ANDCONTINUE 
         PTR=NEXT ANDCONTINUEUNLESS (CURRT_FLAGS!NEXTT_FLAGS)&DONT OPT=0
         J=CURRT_OPERN
         K=NEXTT_OPERN
         UNLESS  FOLD NOOP INFO(J)>>4#0 AND  FOLD NOOP INFO(K)>>4#0 THEN  C 
            PTR=NEXT ANDCONTINUE 
         IF  CURRT_OPND1_FLAG<=1 THEN  OP1=1 AND  OPND1==CURRT_OPND1 ELSE  C 
            OP1=2 AND  OPND1==CURRT_OPND2
         IF  NEXTT_OPND1_FLAG<=1 THEN  OP2=1 AND  OPND2==NEXTT_OPND1 ELSE  C 
            OP2=2 AND  OPND2==NEXTT_OPND2
         CTOPOP=0
         IF  J=K AND  FOLD NOOP INFO(J)&X'80'#0 THEN  CTOPOP=J
         IF  J=K=SUB AND  OP2=2 START 
            IF  OP1=2 THEN  CTOPOP=ADD ELSE  CTOPOP=SUB
         FINISH 
         IF  J=ADD AND  K=SUB AND  OP2=2 THEN  CTOPOP=SUB
         IF  J=SUB AND  K=ADD THENSTART 
            IF  OP1=1 THEN  CTOPOP=ADD ELSE  CTOPOP=SUB
         FINISH 
         IF  CTOPOP#0 START 
            CTOP(CTOPOP,K,0,OPND1,OPND2)
            IF  CTOPOP=0 THENSTART 
               IF  OP2=2 THEN  OPND2==NEXTT_OPND1 ELSE  OPND2==NEXTT_OPND2
               NOOP(NEXT,OPND2)
               CONTINUE 
            FINISH 
         FINISH 
         PTR=NEXT
      REPEAT 
!
! PASS TO CHECK FOR COMMON SUBEXPRESSIONS. DONE IN SUCH A WAY THAT
! SEQUENCES ARE DETECTED AND COMBINED
!
      PTR=TRIPLES(0)_FLINK
      WHILE  PTR>0 CYCLE 
         CURRT==TRIPLES(PTR)
         IF  CURRT_FLAGS&DONT OPT=0 THEN  CHECK DUPS(PTR,CURRT_FLINK)
         PTR=CURRT_FLINK
      REPEAT 
!
! NESTED ACCUMULATOR PASS. AVOID EXCHANGES BY ARRANGING EARLY LOADS
! OF OPERANDS FOR NON COMMUTABLE OPERATIONS
!
      PTR=TRIPLES(0)_FLINK
      WHILE  PTR>0 CYCLE 
         CURRT==TRIPLES(PTR)
         IF  CURRT_OPERN>=128 AND  C 
            CURRT_FLAGS&(LOADOP1!LOADOP2!COMMUTABLE)=LOADOP1 START 
            J=PRELOAD PLACE(CURRT_OPND2_D)
            IF  J>=0 START ;            ! PALCE ACCESSIBLE
               I=J; K=0
               WHILE  I#PTR CYCLE ;     ! CHECK FOR DEPTH OF NESTING
                  NEXTT==TRIPLES(I)
                  IF  K<NEXTT_DPTH THEN  K=NEXTT_DPTH
                  I=NEXTT_FLINK
               REPEAT 
               IF  K+WORDS(CURRT_OPTYPE>>4)>=12 THEN  C 
                  PTR=CURRT_FLINK ANDCONTINUE 
               NEXTT==TRIPLES(J)
               NEWT==TRIPLES(NEXT TRIP)
               NEWT=0
               NEWT_OPERN=PRELOAD;      ! PRELOAD
               NEWT_CNT=1
               NEWT_OPTYPE=CURRT_OPTYPE
               NEWT_FLAGS=LOADOP1!LEAVE STACKED
               NEWT_PUSE=PTR
               NEWT_OPND1=CURRT_OPND1
               CURRT_FLAGS=CURRT_FLAGS&(¬LOAD OP1); ! OP1 DOES NOT NEED LOAD
               CURRT_OPND1_FLAG=REFTRIP
               CURRT_OPND1_D=NEXT TRIP
               CURRT_OPND1_XTRA=0
                                        ! LINK IN NEW TRIPLE
               NEWT_FLINK=J
               NEWT_BLINK=NEXTT_BLINK
               NEXTT_BLINK=NEXT TRIP
               TRIPLES(NEWT_BLINK)_FLINK=NEXT TRIP
               NEXT TRIP=NEXT TRIP+1
!
! CORRECT DEPTH OF NESTING FIELD
!
               NEWT_DPTH=NEXTT_DPTH
               WHILE  J#PTR CYCLE 
                  NEXTT_DPTH=NEXTT_DPTH+WORDS(NEWT_OPTYPE>>4)
                  J=NEXTT_FLINK
                  NEXTT==TRIPLES(J)
               REPEAT 
!               CHANGES=CHANGES+1
            FINISH 
         FINISH 
         PTR=CURRT_FLINK
      REPEAT 
!
! PASS TO TRY TO KEEP DUPLICTE TRIPLES IN ESTACK. THE SAVING
! HERE IS SO LARGE THAT IT IS WORTH THE EFFORT TO FIND THESE
! RATHER RARE CASES. OFTEN THE FORM IS A(I)=A(I)+B.
!
      IF  DUPS>0 START ;                ! THERE IS AT LEST ONE
         PTR=TRIPLES(0)_FLINK
         WHILE  PTR>0 CYCLE 
            CURRT==TRIPLES(PTR)
            NEXT=CURRT_FLINK
            IF  CURRT_CNT=2 START ;     ! ONLY DUPILCATES POSSIBLE
               NEXTT==TRIPLES(NEXT)
               IF  CURRT_PUSE#NEXT AND ((NEXTT_OPND1_FLAG=REFTRIP AND  C 
                  NEXTT_OPND1_D=PTR) OR (NEXTT_OPND2_FLAG=REFTRIP AND  C 
                  NEXTT_FLAGS&(COMMUTABLE!LOADOP1)=COMMUTABLE!LOADOP1 AND  C 
                  NEXTT_OPND2_D=PTR)) START 
                  CURRT_FLAGS=CURRT_FLAGS!USE ESTACK
                  CHANGES=CHANGES+1
                  PTR=NEXT
                  CONTINUE 
               FINISH 
               IF  CURRT_PUSE=NEXT AND  C 
                  NEXTT_OPND1_FLAG=REFTRIP=NEXTT_OPND2_FLAG AND  C 
                  NEXTT_OPND1_D=PTR=NEXTT_OPND2_D THENSTART 
                  CURRT_FLAGS=CURRT_FLAGS!USE ESTACK
                  CHANGES=CHANGES+1
                  PTR=NEXT; CONTINUE 
               FINISH 
               IF  CURRT_PUSE=NEXT AND  NEXTT_FLINK=NEXTT_PUSE#0 AND  C 
                  (NEXTT_FLAGS&COMMUTABLE#0 OR (NEXTT_OPND1_FLAG=REFTRIP AND  C 
                  NEXTT_OPND1_D=PTR)) START 
                  NEWT==TRIPLES(NEXTT_FLINK)
                  IF (NEWT_OPND2_FLAG=REFTRIP AND  NEWT_OPND2_D=PTR) OR  C 
                     (NEWT_FLAGS&COMMUTABLE#0 AND  C 
                     NEWT_OPND1_FLAG=REFTRIP AND  NEWT_OPND1_D=PTR) START 
                        CURRT_FLAGS=CURRT_FLAGS!USE ESTACK
                        CHANGES=CHANGES+1
                        PTR=NEXT
                        CONTINUE 
                  FINISH 
               FINISH 
            FINISH 
            PTR=NEXT
         REPEAT 
      FINISH 
END:
!      %IF CHANGES>0 %AND PARM_DCOMP#0 %THEN PRINT TRIPS(TRIPLES)
      RETURN 
INTEGERFN  PRELOAD PLACE(INTEGER  TRIP)
!***********************************************************************
!*    LOOK FOR FIRST TRIPLE IN THE CHAIN THAT LEADS TO TRIP            *
!*    CAN BE VERY COMPILCATED. RETURN -1 IF NOT SIMPLE                 *
!***********************************************************************
RECORD (RD) NAME  OPND1,OPND2
RECORD (TRIPF) NAME  CURRT
      CURRT==TRIPLES(TRIP)
      OPND1==CURRT_OPND1
      OPND2==CURRT_OPND2
      IF  CURRT_OPERN<128 OR  CURRT_FLAGS&LOAD OP2#0 START ; ! BACK VIA OPND1
         IF  CURRT_FLAGS&LOAD OP1#0 THENRESULT =TRIP
         RESULT =PRELOAD PLACE(OPND1_D)
      FINISH 
      IF  CURRT_FLAGS&LOAD OP1#0 OR  OPND1_D=CURRT_BLINK THEN  C 
         RESULT =PRELOAD PLACE(OPND2_D)
!
! BOTH OPERANDS ARE LOADED TRIPLES
!
      IF  CURRT_BLINK=OPND2_D THENRESULT =PRELOADPLACE(OPND1_D)
      RESULT =-1;                       ! TOO COMPLICATED
END 
ROUTINE  NOOP(INTEGER  TRIPLE NO, RECORD (RD) NAME  ROPND)
!***********************************************************************
!*    THIS TRIPLE HAS BECOME A NOOP.DELETE IT AND PASS ITS ENTRY TRIPLE*
!*    FORWARD TO ANT WHO USE IT                                        *
!***********************************************************************
RECORD (TRIPF) NAME  CURRT,NOOPT
RECORD (RD) NAME  OPND1,OPND2
INTEGER  PTR,CNT
      NOOPT==TRIPLES(TRIPLE NO);        ! THIS ONE TO BECOME NOOP
      CNT=NOOPT_CNT;                    ! HOW MANY TIMES USED
      IMPABORT UNLESS  CNT=1;              ! NO OPS ELIMINATED BEFORE DUPS
      PTR=NOOPT_BLINK
      WHILE  PTR>0 CYCLE 
         CURRT==TRIPLES(PTR)
         IF  CURRT_PUSE=TRIPLE NO THEN  CURRT_PUSE=NOOPT_PUSE
         PTR=CURRT_BLINK
      REPEAT 
      PTR=NOOPT_FLINK
      CYCLE 
         CURRT==TRIPLES(PTR)
         OPND1==CURRT_OPND1
         OPND2==CURRT_OPND2
         IF  (OPND1_FLAG=REFTRIP OR  OPND1_FLAG=INDIRECT) C 
            AND  OPND1_D=TRIPLE NO THENSTART 
            IF  OPND1_FLAG=INDIRECT THEN  RETURN ;! CAN OPTIMISE AT PRESESNT
            OPND1=ROPND
            CNT=CNT-1
            IF  OPND1_FLAG#REFTRIP THEN  CURRT_FLAGS=CURRT_FLAGS!LOAD OP1
         FINISH 
         IF  CURRT_OPERN>=128 AND  OPND2_D=TRIPLE NO AND  C 
            (OPND2_FLAG=REFTRIP OR  OPND2_FLAG=INDIRECT)  START 
            IF  OPND2_FLAG=INDIRECT THEN  RETURN 
            OPND2=ROPND
            CNT=CNT-1
            IF  OPND2_FLAG#REFTRIP THEN  CURRT_FLAGS=CURRT_FLAGS!LOAD OP2
         FINISH 
         PTR=CURRT_FLINK
         IF  CNT=0 OR  PTR=0 THENEXIT 
         IF  NOOPT_OPND1_FLAG#REFTRIP THEN  C 
            CURRT_DPTH<-CURRT_DPTH-WORDS(NOOPT_OPTYPE>>4)
      REPEAT 
      NOOPT_X1=NOOPT_OPERN;             ! FOR DEBUGGING
      NOOPT_OPERN=NULLT;                ! SET AS NOOP
      CHANGES=CHANGES+1
END 
ROUTINE  DEC USE(INTEGER  TRIPLE NO)
!***********************************************************************
!*    A TRIPLE HAS BEEN PASSED INTO 'DEAD' CODE. DECREMENT ITS USE     *
!*    AND IF RELEVANT DELETE OPERATIONS LEADING TO IT                  *
!***********************************************************************
RECORD (TRIPF) NAME  CURRT
      CURRT==TRIPLES(TRIPLE NO)
      CURRT_CNT=CURRT_CNT-1
      IF  CURRT_CNT=1 THEN  DUPS=DUPS-1
      IF  CURRT_CNT=0 THEN  DELETE TRIPLE(TRIPLE NO)
END 
ROUTINE  DELETE TRIPLE(INTEGER  TRIPLE NO)
RECORD (TRIPF) NAME  DELT
      DELT==TRIPLES(TRIPLE NO)
      IF  DELT_OPND1_FLAG=REFTRIP OR  DELT_OPND1_FLAG=INDIRECT THEN  C 
         DEC USE(DELT_OPND1_D)
      IF  DELT_OPERN>=128 AND (DELT_OPND2_FLAG=REFTRIP OR  C 
         DELT_OPND2_FLAG=INDIRECT) THEN  DEC USE(DELT_OPND2_D)
      DELT_X1=DELT_OPERN;               ! FOR DEBUGGING
      DELT_OPERN=NULLT;                 ! NO OP
END 
ROUTINE  DUPLICATE TRIP(INTEGER  TRIPNO,DTRIPNO)
!***********************************************************************
!*    DTRIPNO IS A DUPLICATE OF TRIPNO. CHANGE ALL REFERENCES          *
!*    AND DELETE IT                                                    *
!***********************************************************************
RECORD (RD) NAME  OPND1,OPND2
RECORD (TRIPF) NAME  MASTER,CURRT,DUPT
INTEGER  CNT,PTR
      DUPS=DUPS+1
      DUPTNO=TRIPNO
      MASTER==TRIPLES(TRIPNO)
      DUPT==TRIPLES(DTRIPNO)
      CNT=DUPT_CNT
      PTR=DUPT_FLINK
!
      WHILE  CNT>0 AND  PTR>0 CYCLE 
         CURRT==TRIPLES(PTR)
         OPND1==CURRT_OPND1
         OPND2==CURRT_OPND2
         IF  OPND1_D=DTRIPNO AND (OPND1_FLAG=REFTRIP OR  C 
            OPND1_FLAG=INDIRECT) START 
            MASTER_CNT=MASTER_CNT+1
            OPND1_D=TRIPNO
            CURRT_FLAGS=CURRT_FLAGS!LOAD OP1
            CNT=CNT-1
         FINISH 
         IF  CURRT_OPERN>=128 AND  OPND2_D=DTRIPNO AND  C 
            (OPND2_FLAG=REFTRIP OR  OPND2_FLAG=INDIRECT) START 
            MASTER_CNT=MASTER_CNT+1
            OPND2_D=TRIPNO
            CURRT_FLAGS=CURRT_FLAGS!LOAD OP2
            CNT=CNT-1
         FINISH 
         PTR=CURRT_FLINK
      REPEAT 
      DELETE TRIPLE(DTRIPNO)
END 
ROUTINE  CHECK DUPS(INTEGER  TRIPNO,STRIPNO)
!***********************************************************************
!*    CHECK STARTING FROM STRIPNO FOR DUPLICATES OF TRIPNO             *
!*    MAY BE MORE THAN ONE                                             *
!***********************************************************************
RECORD (TRIPF) NAME  CURRT,DUPT
INTEGER  OPERN,F,NEXT
      DUPT==TRIPLES(TRIPNO)
      OPERN=DUPT_OPERN
      F=DUPT_FLAGS
      WHILE  STRIPNO>0 CYCLE 
         CURRT==TRIPLES(STRIPNO)
         EXITIF  CURRT_OPERN=TLAB OR  CURRT_OPERN=RTXIT OR  CURRT_OPERN=RCALL
         EXITIF  CURRT_OPERN=VASS OR  CURRT_OPERN=VJASS
         NEXT=CURRT_FLINK
         IF  CURRT_OPERN=OPERN AND ((OPERN<128 AND  C 
            SAME OPND(DUPT_OPND1,CURRT_OPND1)=YES) OR (OPERN>=128 AND  C 
            SAME OPND(DUPT_OPND1,CURRT_OPND1)=YES AND  C 
            SAME OPND(DUPT_OPND2,CURRT_OPND2)=YES) OR (F&COMMUTABLE#0 AND  C 
            SAME OPND(DUPT_OPND1,CURRT_OPND2)=YES AND  C 
            SAME OPND(DUPT_OPND2,CURRT_OPND1)=YES)) START 
            DUPLICATE TRIP(TRIPNO,STRIPNO)
            CHANGES=CHANGES+1
         FINISH 
         STRIPNO=NEXT
      REPEAT 
END 
INTEGERFN  SAME OPND(RECORD (RD) NAME  OPND1,OPND2)
!***********************************************************************
!*    ARE THESE OPERANDS THE SAME ?                                    *
!***********************************************************************
INTEGER  F,I
      RESULT =NO UNLESS  OPND1_S1=OPND2_S1
      F=OPND1_FLAG
      IF  F=2 OR  F=5 START 
         RESULT =NO UNLESS  OPND1_XTRA=OPND2_XTRA AND  OPND1_PTYPE&X'3000'=0
         RESULT =YES
      FINISH 
      IF  F<=1 START ;                  ! CONSTANTS
         IF  OPND1_PTYPE=X'35' START 
            RESULT =NO UNLESS  OPND1_XTRA=OPND2_XTRA
            FOR  I=1,1,OPND1_XTRA CYCLE 
               RESULT =NO UNLESS  A(OPND1_D+I)=A(OPND2_D+I)
            REPEAT 
            RESULT =YES
         FINISH 
         RESULT =YES IF  OPND1_D=OPND2_D AND (OPND1_XTRA=OPND2_XTRA OR  C 
            OPND1_PTYPE&X'F0'<=X'50')
         RESULT =NO
      FINISH 
      RESULT =YES IF  OPND1_D=OPND2_D AND  OPND1_XTRA=OPND2_XTRA
      RESULT =NO
END 
END 
ENDOFFILE