INCLUDE  "ERCC07.TRIMP_TFORM1S"
INCLUDE  "ERCC07.TRIPCNSTS"
EXTRINSICRECORD  (WORKAF) WORKA
EXTRINSICRECORD  (PARMF) PARM
EXTERNALROUTINESPEC  IMPABORT
EXTERNALROUTINESPEC  MOVE BYTES(INTEGER  L,FB,FO,TB,TO)
EXTERNALROUTINESPEC  FAULT(INTEGER  N,DATA,IDENT)
EXTERNALROUTINESPEC  PRINT TRIPS(RECORD  (TRIPF) ARRAYNAME  TRIPLES)
CONSTBYTEINTEGERARRAY  WORDS(0:7)=0(3),1,1,1,2,4;
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             *
!***********************************************************************
ROUTINESPEC  EXTRACT(RECORD  (RD) NAME  OPND)
CONSTINTEGER  UTRUNCMASK=X'00000800',BTRUNCMASK=X'00000013'
INTEGER  K,TYPEP,PRECP,OP,MAXD,SVAL1,SVAL2,C,D,JJ,KK,TRUNCMASK
STRING  (255) STRVAL,STRVAL1,STRVAL2
      IF  1<<HOST&LINTAVAIL#0 THENSTART 
      LONGINTEGER  VAL,VAL1,VAL2
      FINISHELSESTART 
      INTEGER  VAL,VAL1,VAL2
      FINISH 
      IF  1<<HOST&LLREALAVAIL#0 THENSTART 
      LONGLONGREAL  RVAL,RVAL1,RVAL2
      FINISHELSESTART 
      LONGREAL  RVAL,RVAL1,RVAL2
      FINISH 
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
      RETURN  IF  1<<HOST&LINTAVAIL=0 AND  OPND1_PTYPE=X'61'
      RETURN  IF  1<<HOST&LLREALAVAIL=0 AND  OPND1_PTYPE=X'72'
      EXTRACT(OPND1)
      VAL1=VAL; RVAL1=RVAL; STRVAL1=STRVAL
      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=VAL; RVAL2=RVAL; STRVAL2=STRVAL
      SVAL2<-VAL2
      IF  TYPEP=2 THEN  ->BRSW(OP) ELSE  ->BISW(OP)
UISW(10):                               ! ¬
      VAL1=¬VAL1
INTEND:
      IF  1<<HOST&LINTAVAIL#0 AND  PRECP=6 THENSTART 
         OPND1_D<-VAL1>>32
         OPND1_XTRA<-VAL1
         FLAG=0
      FINISHELSESTART 
         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
         OPND1_FLAG=0
      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=SCONST
      IF  PRECP=5 THEN  OPND1_R=RVAL1 ELSEIF  PRECP=6 THEN  C 
         OPND1_LR=RVAL1 ELSESTART 
         OPND1_FLAG=LCONST
         OPND1_D=WORKA_ARTOP
         WORKA_ARTOP=WORKA_ARTOP+16
         MOVE BYTES(16,ADDR(RVAL1),0,ADDR(WORKA_A(0)),OPND1_D)
      FINISH 
      FLAG=0; OPND1_PTYPE=16*PRECP+2
      RETURN 
UISW(15):                               ! STRETCH INTEGER
      IF  1<<HOST&LINTAVAIL#0 AND  PRECP=5 THEN  PRECP=6 AND  ->INT END
      IF  PRECP=4 THEN  PRECP=5 AND  ->INT END
      RETURN 
UISW(14):                               ! SHORTEN INTEGER
      IF  IMOD(VAL1)<=X'7FFF' THEN  PRECP=4 AND  ->INT END
      IF  PRECP=6 AND  VAL1=SVAL1 THEN  PRECP=5 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
      MAXD=OPND2_D>>16&31;                 ! MAX DIMENSION
      C=OPND2_D>>24;                       ! DIMENSION
      D=OPND2_D&X'FFFF';                   ! DV POINTER
      RETURNUNLESS  D>0;                ! UNLESS DV AVAILABLE
      IF  TARGET=PNX OR  TARGET=PERQ OR  TARGET=ACCENT START 
         IF  VAL1<WORKA_CTABLE(D+3*C+1) OR  VAL1>WORKA_CTABLE(D+3*C) THEN  C 
            FAULT(50,VAL1,XTRA&X'FFFF')
         VAL1=VAL1*WORKA_CTABLE(D+3*C-1) UNLESS  C=1
         ->INT END
      FINISH 
      IF  TARGET=EMAS START 
         C=3*(MAXD+1-C)
         JJ=(VAL1-WORKA_CTABLE(D+C))*WORKA_CTABLE(D+C+1)
         IF  JJ<0 OR  JJ>WORKA_CTABLE(D+C+2) THEN  FAULT(50,VAL1,XTRA&X'FFFF')
         VAL1=JJ
         ->INT END
      FINISH 
      IF  TARGET=IBM OR  TARGET=IBMXA START 
         IF  VAL1<WORKA_CTABLE(D+3*C) OR  VAL1>WORKA_CTABLE(D+3*C+1) C 
            THEN  FAULT(50,VAL1,XTRA&X'FFFF')
            VAL1=VAL1*WORKA_CTABLE(D+3*C+2)
         ->INTEND
      FINISH 
      RETURN 
BISW(18):                               ! ARRAY SCALE
      IF  TARGET=PERQ OR  TARGET=ACCENT OR  TARGET=PNX START 
         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
      FINISH 
      ->INT END
BISW(11):
BISW(12):                               ! COMPARISONS
BRSW(11):
BRSW(12):                               ! REAL COMPARISONS
      MASK=XTRA;                        ! XTRA HAS IBM TYPE MASK
                                        ! RETURN MASK AS 15(=JUMP) OR 0 (IGNORE)
      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
      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(*):
      RETURN 
ROUTINE  EXTRACT(RECORD  (RD) NAME  OPND)
!***********************************************************************
!*    EXTRACTS A CONTANT OPERAND RETURNING REAL &INT VALUES           *
!***********************************************************************
INTEGER  TYPE,PREC,I,AD
      TYPE=OPND_PTYPE; PREC=TYPE>>4
      TYPE=TYPE&15
      VAL=0; RVAL=0; STRVAL=""
      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  1<<HOST&LINTAVAIL#0 AND  PREC=6 THEN  C 
            VAL=LENGTHENI(OPND_D)<<32!(OPND_XTRA&(LENGTHENI(-1)>>32)) C 
            ELSE  VAL=OPND_D
         RVAL=VAL
      FINISHELSESTART 
         IF  PREC=5 THEN  RVAL=OPND_R ELSE  C 
            IF  PREC=6 THEN  RVAL=OPND_LR ELSE  C 
            MOVE BYTES(16,ADDR(WORKA_A(0)),OPND_D,ADDR(RVAL),0)
      FINISH 
END 
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,COP
CONSTINTEGER  FOLDI=X'1C00007F';        ! FOLD 10-16 & 36-38
CONSTINTEGER  FOLDR=X'0107FFFF';        ! FOLD 128-146 &152
RECORD  (TRIPF) NAME  CURRT,REFT
ROUTINESPEC  BACKTRACK(RECORD (TRIPF)NAME  CURRT)
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
         COP=CURRT_OPERN;               ! CURRENT OPERATION
         INSPECT OPND(1)
         IF  COP>=128 THEN  INSPECT OPND(2)
!
         IF  CURRT_FLAGS&CONSTANTOP#0 AND  ((COP<128 AND  C 
            FOLDI&1<<(COP-10)#0) OR  (CURRT_OPND1_FLAG<=1 AND  C 
            CURRT_OPND2_FLAG<=1 AND  FOLDR&1<<(COP&31)#0)) START 
            I=COP
            CTOP(I,J,CURRT_X1,CURRT_OPND1,CURRT_OPND2)
            IF  I=0 THENSTART 
               CURRT_X1=COP;    ! FOR DEBUGGING OPTIMISATIONS
               CURRT_OPERN=NULLT
               REPLACE TRIPREF(CURR TRIPNO,CURRT_OPND1)
            FINISH 
         FINISH 
         IF  COP=LASS AND  CURRT_FLAGS&CONSTANTOP#0 AND  C 
            CURRT_CNT>0 THEN  REPLACE TRIPREF(CURRTRIPNO,CURRT_OPND2)
         IF  TARGET=PNX OR  TARGET=PERQ OR  TARGET=ACCENT START 
            CURRT_DPTH<-DEPTH
            IF  CURRT_CNT>0 AND  C 
               (TARGET=PERQ OR  TARGET=ACCENT OR  CURRT_OPTYPE&7=1) THEN  C 
               DEPTH=DEPTH+WORDS(CURRT_OPTYPE>>4)
         FINISH 
         IF  TARGET=EMAS START ;        ! DO SOME CRUDE REGISTER ALLOCATION
            CURRT_DPTH=0;               ! USE ACCR
            IF  COP=VMY OR  COP=COMB OR  COP=BADJ C 
               OR  COP=FORPRE OR  COP=FORPR2 OR  COP=FOREND C 
               THEN  CURRT_DPTH=7;      ! USE BREG
            IF  CURRT_OPTYPE=X'35' AND  COP=PRELOAD THEN  C 
               CURRT_DPTH=1;            ! USE DR
            IF  COP=VMY THEN  BACK TRACK(CURRT)
         FINISH 
      REPEAT 
      RETURN 
ROUTINE  BACKTRACK(RECORD (TRIPF)NAME  CURRT)
!***********************************************************************
!*    TRIES TO GET ALL OPERANDS OF A VMY EVALUATED IN B                *
!***********************************************************************
INTEGER  I
RECORD (RD)NAME  OPND
RECORD (TRIPF)NAME  REFT
      IF  TARGET=EMAS START ;           ! EMAS ONLY OPTIMISATION
         FOR  I=1,1,2 CYCLE 
            IF  I=1 THEN  OPND==CURRT_OPND1 ELSE  OPND==CURRT_OPND2
            IF  OPND_FLAG=REFTRIP AND (CURRT_OPERN#SUB OR  I=1) START 
               REFT==TRIPLES(OPND_D)
               IF  REFT_OPERN=ADD OR  REFT_OPERN=MULT OR  C 
                  REFT_OPERN=SUB THEN  START 
                  REFT_DPTH=7
                  BACK TRACK(REFT)
               FINISH 
            FINISH 
            EXIT  IF  CURRT_OPERN<128
         REPEAT 
      FINISH 
END 
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,
                                        LOADOP2(2){ASS AND JAM ASS},
                                        LOADOP1{****},
                                        LOADOP1{SCALE},
                                        LOADOP1!LOADOP2,
                                        LOADOP2{INDEXED FETCH},
                                        LOADOP2{LASS},
                                        LOADOP1!LOADOP2(3),
                                        LOADOP2{IOCP DONT LOAD EPNO},
                                        LOADOP2(6){P PASSING},
                                        0(6){LABELS AND SWITCH DECLS},
                                        LOADOP2{GOTO SW LOAD OPERAND},
                                        LOADOP2(7){STR,PTR&RESULT ASSMNT},
                                        LOADOP1!LOADOP2(2){STR COMP&DCOMP},
                                        LOADOP2(2){PRE RES DONT LD WKAREA},
                                        LOADOP1{RESLN DONT LOAD LABEL},
                                        LOADOP2{RES FINALE DONT LOAD WKAREA},
                                        LOADOP1!LOADOP2{SIG EVNT UNUSED},
                                        LOADOP2{REC ASSNMNT},
                                        LOADOP1!LOADOP2(*)

INTEGER  I,LOADOP,OPERN
      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  1<<OPND_FLAG&BTREFMASK#0 START 
         RTRIP==TRIPLES(OPND_D)
         OPERN=RTRIP_OPERN
         IF  RTRIP_PUSE#CURRTRIPNO OR  OPERN=PRECC OR  C 
            (OPERN=LASS AND  RTRIP_FLINK#CURRTRIPNO) OR  C 
            OPERN=CONCAT OR  OPERN=ITOS1 THEN  C 
            CURRT_FLAGS=CURRT_FLAGS!LOADOP
         IF  TARGET=PNX AND  RTRIP_PUSE=CURRTRIPNO AND  RTRIP_OPTYPE&7=1 THEN  C 
            DEPTH=DEPTH-WORDS(RTRIP_OPTYPE>>4)
         IF  (TARGET=PERQ OR  TARGET=ACCENT) AND  RTRIP_PUSE=CURRTRIPNO C 
            THEN  DEPTH=DEPTH-WORDS(RTRIP_OPTYPE>>4)
      FINISH 
END 
ROUTINE  REPLACE TRIPREF(INTEGER  TRIP, RECORD  (RD) NAME  OPND)
INTEGER  PTR,COUNT
RECORD  (TRIPF) NAME  RTRIP
      PTR=STPTR
      COUNT=TRIPLES(TRIP)_CNT
      TRIPLES(TRIP)_CNT=0
      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,XVAL,CURR,NEXT,OP1,OP2,
         CTOPOP,REVOP,APTYPE
BYTEINTEGERARRAYNAME  A
RECORD  (TRIPF) NAME  CURRT,NEWT,NEXTT
RECORD  (RD) NAME  OPND1,OPND2,POPND
ROUTINESPEC  SWOP OPERANDS(RECORD  (TRIPF) NAME  CURRT)
INTEGERFNSPEC  POWEROF2(INTEGER  VAL)
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'89',X'41',X'89',X'89',X'B6',{+,-,!!,!,*} C 
                    2,0,X'A4',1,1,{//,/,&,>>,<<} C 
                    2,0,0,3,X'89',{**,COMP,DCOMP,VMY,COMB} C 
                    0,0,2,0,1,{=,<-,****,SCALE,INDEX} C 
                    0{IFETCH},0(3),
                    X'40'{CONCAT},0(*)

! 2**0 SET IF SECOND OPERAND ZERO IS NOOP
! 2**1 SET IF SECOND OPERAND 1 IS A NOOP
! 2**2 SET IF SECOND OPERAND 0 MEANS RESULT=0
! 2**3 SET IF FIRST OPERAND ZERO IS NOOP
! 2**4 SET IF FIRST OPERAND 1 IS A NOOP
! 2**5 SET IF  FIRST OPERAND ZERO MEANS RESULT=0
! 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
!
! 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)
         WHILE  NEXTT_OPERN=NULLT AND  NEXTT_FLINK>0 CYCLE 
            NEXT=NEXTT_FLINK;           ! SKIP OVER ANY NOOPS
            NEXTT==TRIPLES(NEXT)
         REPEAT 
         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)>>6#0 AND  FOLD NOOP INFO(K)>>6#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; REVOP=0
         IF  J=K AND  FOLD NOOP INFO(J)&X'80'#0 THEN  CTOPOP=J
         IF  J=K=SUB START 
            IF  OP2=2 START 
               IF  OP1=2 THEN  CTOPOP=ADD ELSE  CTOPOP=SUB
            FINISHELSESTART ;           ! OP2=1 CASE
               IF  OP1=1 THEN  CTOPOP=SUB AND  REVOP=ADD ELSE  CTOPOP=ADD
            FINISH 
         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  J=K=CONCAT AND  OP1=OP2=2 THEN  CTOPOP=CONCAT
         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)
               IF  REVOP#0 THEN  CURRT_OPERN=REVOP
               CONTINUE 
            FINISH 
         FINISH 
         PTR=NEXT
      REPEAT 
!      %IF CHANGES>0 %THEN PRINT TRIPS(TRIPLES)
!
! FIRST REAL OPTIMISATION 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
!
! ALSO DOES A FEW REARRANGEMENTS OF SIMPLE COMPARISONS AND ARITHMETICS
!
      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
         IF  (TARGET=EMAS OR  TARGET=IBMXA) AND  I=MULT C 
            AND  CURRT_CNT=1 START 
            NEXTT==TRIPLES(CURRT_PUSE)
            IF  NEXTT_OPERN=LNGTHN START 
               CURRT_OPTYPE=CURRT_OPTYPE+X'10'
               NEXTT_OPND1_PTYPE=NEXTT_OPND1_PTYPE+X'10'
               I=MULTX
               CURRT_OPERN=MULTX
               NOOP(CURRT_PUSE,NEXTT_OPND1)
            FINISH 
         FINISH 
         CONTINUE  IF  CURRT_FLAGS&CONSTANTOP=0
         OPND1==CURRT_OPND1
         OPND2==CURRT_OPND2
         IF  OPND1_FLAG<=1 THEN  C 
            OP1=1 AND  VAL=OPND1_D AND  XVAL=OPND1_XTRA ELSE  C 
            OP1=2 AND  VAL=OPND2_D AND  XVAL=OPND2_XTRA
         IF  I=DCOMP AND  OP1=2 START ; ! EXPAND I=0=J ETC
            I=COMP; CURRT_OPERN=COMP
            NEXTT==TRIPLES(CURRT_PUSE)
            NEXTT_OPND1=OPND2
            NEXTT_FLAGS=NEXTT_FLAGS!LOADOP1
         FINISH 
         IF  I=COMP START 
            J=CURRT_X1&15;              ! IBM COND MASK
            IF  CURRT_OPTYPE&7=1 START ; ! TRANSFORM I>=1 TO I>0 ETC
               IF  (OP1=2 AND  ((VAL=1 AND  (J=4 OR  J=10)) OR  (VAL=-1 AND  C 
                  (J=2 OR  J=12)))) OR  (OP1=1 AND  ((VAL=1 AND  (J=2 OR  C 
                  J=12)) OR  (VAL=-1 AND  (J=4 OR  J=10)))) START 
                  J=J!!8
                  CURRT_X1=CURRT_X1!!8
                  NEXTT==TRIPLES(CURRT_FLINK)
                  NEXTT_X1=NEXTT_X1!!8; ! ALSO ALTER MASK IN THE JUMP
                  VAL=0
                  IF  OP1=2 THEN  OPND2_D=0 ELSE  OPND1_D=0
               FINISH 
            FINISH 
            IF  VAL=0 AND  (XVAL=0 OR  CURRT_OPTYPE>>4<=5) AND  C 
               (TARGET=EMAS OR 7<=J<=8)  START 
               CURRT_OPERN=ZCOMP
               IF  OP1=1 THEN  SWOP OPERANDS(CURRT)
               CURRT_FLAGS=CURRT_FLAGS&(¬LOADOP2)!DONT OPT
            FINISH 
         FINISH 
         IF  (TARGET=PNX OR  TARGET=EMAS OR  TARGET=IBMXA) AND  C 
            (I=LSHIFT OR  I=RSHIFT) AND  1<=VAL<=31 AND  OP1=2 START 
                                        ! <<CONST AND >> CONST
            CURRT_OPERN=CLSHIFT
            IF  I=RSHIFT THEN  VAL=-VAL AND  OPND2_D=VAL
            I=CLSHIFT
            CURRT_FLAGS=CURRT_FLAGS&(¬LOADOP2)
         FINISH 
!         %IF I=INTDIV %AND OP1=2 %AND VAL>1 %START
!            J=POWEROF2(VAL)
!            %IF J>0 %START
!               CURRT_OPERN=CASHIFT
!               I=CASHIFT
!               OPND2_D=-J
!               CURRT_FLAGS=CURRT_FLAGS&(¬LOADOP2)
!            %FINISH
!         %FINISH
!
! THE ABOVE OPTIMISATION IS UNSOUND FOR NEGATIVE OPERANDS
!
         UNLESS  TARGET=PERQ OR  TARGET=ACCENT START 
                                        ! THESE HAVE NO ARITHMETIC SHIFT
            IF  I=MULT AND  VAL>1 AND  CURRT_OPTYPE&15=1 START 
               J=POWEROF2(VAL)
               IF  J>0 START 
                  IF  OP1=1 THEN  SWOP OPERANDS(CURRT)
                  CURRT_OPERN=CASHIFT
                  I=CASHIFT
                  OPND2_D=J
                  CURRT_FLAGS=CURRT_FLAGS&(¬LOADOP2)
               FINISH 
            FINISH 
         FINISH 
         IF  I>=128 THENSTART ;         ! BINARY OPERATIONS
            IF  I=VMY START ;           ! SOME VMY ARE NO OPS
               IF  TARGET=PNX OR  TARGET=PERQ OR  TARGET=ACCENT C 
                   THEN  VAL=VAL>>24;   ! DIM=1 IS NOOP
               IF  TARGET=EMAS START 
                  APTYPE=CURRT_X1>>16
                  IF  APTYPE>>8=2 AND  APTYPE&7<=2 AND  APTYPE&255#X'41' C 
                     THEN  VAL=VAL>>24; ! DIMEN 1 IS NOOP
                  FINISH 
               FINISH 
            J=FOLD NOOP INFO(I)&X'3F'
            CONTINUEUNLESS  VAL<=1 AND  J#0 AND  CURRT_OPTYPE&7=1
            POPND==OPND1;               ! FOR PASSING FORWARD
            IF  OP1=1 THEN  K=3 AND  POPND==OPND2 ELSE  K=0
! BIT SHIFT FOR MASK
            IF  (J&(1<<K)#0 AND  VAL=0) OR  (J&(2<<K)#0 AND  VAL=1) START 
               NOOP(CURR,POPND);        ! THIS IS NOOP
               CONTINUE 
            FINISH 
            IF  J&(4<<K)#0 AND  VAL=0 THENSTART 
               IF  OPND1_FLAG=REFTRIP THEN  DEC USE(OPND1_D)
               IF  OP1=2 THEN  OPND1=OPND2; ! RESULT IS ZERO
               NOOP(CURR,OPND1)
                                        ! MAY CAUSE OTHER NOOPS
                                        ! GE I=(A+B)*0
            FINISH 
            IF  VAL=0 AND  OP1=1 AND  CURRT_OPERN=SUB THEN  C 
               OPND1=OPND2 AND  CURRT_OPERN=LNEG
                                        ! OPTIMISE"0-X"
         FINISH  ELSE  START ;          ! UNARY OPERATORS
                                        ! CAN OPTIMISE LOAD DOUBLE & SHRINK
                                        ! FOR PERQ & ACCENT
         FINISH 

      REPEAT 
!      %IF CHANGES>0 %AND PARM_DCOMP#0 %THEN CHANGES=0 %AND PRINT TRIPS(TRIPLES)
!
! LOOK FOR REGISTER TO STORE OPERATIONS ON PNX
!
      IF  TARGET=PNX START 
         PTR=TRIPLES(0)_FLINK
         WHILE  PTR>0 CYCLE 
            CURRT==TRIPLES(PTR)
            PTR=CURRT_FLINK
            NEXTT==TRIPLES(PTR)
            EXIT  IF  PTR=0;            ! THE END
            UNLESS  NEXTT_OPERN=VASS AND  NEXTT_OPTYPE=X'51'=CURRT_OPTYPE C 
               AND  (NEXTT_OPND1_FLAG=DNAME OR  NEXTT_OPND1_FLAG=INDNAME) C 
               AND  NEXTT_OPND2_FLAG=REFTRIP AND  C 
               CURRT_PUSE=PTR AND  CURRT_CNT=1 THEN  CONTINUE 
            CONTINUE  UNLESS  ADD<=CURRT_OPERN<=LSHIFT
            IF  CURRT_FLAGS&COMMUTABLE#0 AND  C 
               SAME OPND(CURRT_OPND2,NEXTT_OPND1)=YES THEN  C 
               SWOP OPERANDS(CURRT) ELSE  START 
                 CONTINUE  UNLESS  SAME OPND(CURRT_OPND1,NEXTT_OPND1)=YES
            FINISH 
            CURRT_X1=CURRT_OPERN
            CURRT_OPERN=RSTORE
            CURRT_PUSE=0
            CURRT_FLAGS=CURRT_FLAGS&(¬LOAD OP1);! THIS AVOIDS A USELESS PRELOAD
            DELETE TRIPLE(PTR)
         REPEAT 
      FINISH 
!
! 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
!
      IF  TARGET=PNX OR  TARGET=PERQ OR  TARGET=ACCENT START 
         PTR=TRIPLES(0)_FLINK
         WHILE  PTR>0 CYCLE 
            CURRT==TRIPLES(PTR)
            IF  CURRT_OPERN>=128 AND  CURRT_OPERN#VASS AND  C 
               CURRT_OPERN#VJASS AND  C 
               (TARGET=PERQ OR  TARGET=ACCENT OR  CURRT_OPTYPE&7=1) AND  C 
               CURRT_FLAGS&(LOADOP1!LOADOP2!COMMUTABLE)=LOADOP1 AND  C 
               CURRT_OPND2_FLAG=REFTRIP AND  1<<CURRT_OPND1_FLAG&BTREFMASK=0 START 
               J=PRELOAD PLACE(CURRT_OPND2_D)
               IF  J>=0 AND  CURRT_DPTH=TRIPLES(J)_DPTH START 
                                       ! PLACE ACCESSIBLE
                  I=J; K=0
                  WHILE  I#PTR CYCLE ;  ! CHECK FOR DEPTH OF NESTING
                     NEXTT==TRIPLES(I)
!                  PRINTSTRING("TRIPLE EXAMINED")
!               WRITE(I,5); WRITE(OP1,5)
!                  NEWLINE
                     IF  NEXTT_DPTH<CURRT_DPTH THEN  K=999 AND  EXIT 
                                        ! LOWER ESTACK ITEMS WILL BE USED
                                        ! CANOT PRELOAD THIS ITEM
                     OP1=NEXTT_OPERN
                     IF  OP1=IOCPC OR  OP1=PRECL OR  OP1=RCALL OR  C 
                        OP1=RCRFR OR  OP1=RCRMR THEN  C 
                        K=999 ANDEXIT 
                     IF  K<NEXTT_DPTH THEN  K=NEXTT_DPTH
                     I=NEXTT_FLINK
                  REPEAT 
                  IF  K+WORDS(CURRT_OPTYPE>>4)>=6 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 
      FINISH 
!
! 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  (TARGET=PNX OR  TARGET=PERQ OR  TARGET=ACCENT) C 
         AND  DUPS>0 START ;            ! THERE IS AT LEST ONE
         PTR=TRIPLES(0)_FLINK
         WHILE  PTR>0 CYCLE 
            CURRT==TRIPLES(PTR)
            NEXTT==CURRT
            CYCLE 
               NEXT=NEXTT_FLINK
               NEXTT==TRIPLES(NEXT)
            REPEATUNTIL  NEXTT_OPERN#NULLT
            IF  CURRT_CNT=2 AND  C 
               (TARGET=PERQ OR  TARGET=ACCENT OR  CURRT_OPTYPE&7=1) START ; ! ONLY DUPILCATES POSSIBLE
               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  C 
                  (NEXTT_OPND1_FLAG=REFTRIP AND  NEXTT_OPND1_D=PTR)) START 
                  NEWT==TRIPLES(NEXTT_FLINK)
                  NEWT==TRIPLES(NEWT_FLINK) WHILE  NEWT_OPERN=NULLT
                  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 
!      %IF CHANGES>0 %AND PARM_DCOMP#0 %THEN PRINT TRIPS(TRIPLES)
      RETURN 
INTEGERFN  POWEROF2(INTEGER  VAL)
!***********************************************************************
!*    CHECKS IF VAL IS A POWER OF 2                                    *
!***********************************************************************
INTEGER  I,J
      FOR  I=1,1,30 CYCLE 
         J=1<<I
         IF  J=VAL THENRESULT =I
         IF  J>VAL THENRESULT =0
      REPEAT 
      RESULT =0
END 
ROUTINE  SWOP OPERANDS(RECORD  (TRIPF) NAME  CURRT)
!***********************************************************************
!*    EXCHANGE OPND1&OPND2 KEEPING THE FLAGS CORRECT                   *
!***********************************************************************
RECORD  (RD) TOPND
INTEGER  FLAGS,NEWFLAGS
      TOPND=CURRT_OPND1
      CURRT_OPND1=CURRT_OPND2
      CURRT_OPND2=TOPND
      FLAGS=CURRT_FLAGS
      NEWFLAGS=FLAGS&(¬(LOADOP1+LOADOP2))
      IF  FLAGS&LOADOP1#0 THEN  NEWFLAGS=NEWFLAGS!LOADOP2
      IF  FLAGS&LOADOP2#0 THEN  NEWFLAGS=NEWFLAGS!LOADOP1
      CURRT_FLAGS=NEWFLAGS
END 
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                 *
!***********************************************************************
CONSTINTEGER  TRIPREFS=X'140';          ! BITMASK OF OPERAND FORMATS
RECORD  (RD) NAME  OPND1,OPND2
RECORD  (TRIPF) NAME  CURRT
      CURRT==TRIPLES(TRIP)
      OPND1==CURRT_OPND1
      OPND2==CURRT_OPND2
      IF  CURRT_OPERN<128 OR  1<<CURRT_OPND2_FLAG&TRIPREFS=0 START 
                                        ! BACK VIA OPND1
         IF  1<<CURRT_OPND1_FLAG&TRIPREFS=0 THENRESULT =TRIP
         RESULT =PRELOAD PLACE(OPND1_D)
      FINISH 
      IF  1<<CURRT_OPND1_FLAG&TRIPREFS=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)
         PTR=CURRT_FLINK
         CONTINUEIF  CURRT_OPERN=NULLT
         OPND1==CURRT_OPND1
         OPND2==CURRT_OPND2
         IF  (OPND1_FLAG=REFTRIP OR  OPND1_FLAG=INDIRECT) AND  C 
            OPND1_D=TRIPLE NO THENSTART 
            IF  OPND1_FLAG=INDIRECT THENRETURN ; ! 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 THENRETURN 
            OPND2=ROPND
            CNT=CNT-1
            IF  OPND2_FLAG#REFTRIP THEN  CURRT_FLAGS=CURRT_FLAGS!LOAD OP2
         FINISH 
         IF  CNT=0 OR  PTR=0 THENEXIT 
         IF  1<<NOOPT_OPND1_FLAG&BTREFMASK=0  AND  C 
         (TARGET=PERQ OR  TARGET=ACCENT OR  C 
         (TARGET=PNX AND  NOOPT_OPTYPE&7=1))THEN  C 
            CURRT_DPTH<-CURRT_DPTH-WORDS(NOOPT_OPTYPE>>4)
      REPEAT 
      NOOPT_X1=NOOPT_OPERN;             ! FOR DEBUGGING
      NOOPT_OPERN=NULLT;                ! SET AS NOOP
      NOOPT_PUSE=0
      NOOPT_FLAGS=NOOPT_FLAGS!DONT OPT; ! SKIP DUP CHECKING
      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 AND  CURRT_OPERN#RSTORE 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
      CHANGES=CHANGES+1
      DELT_FLAGS=DELT_FLAGS!DONT OPT
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)
         PTR=CURRT_FLINK
         IF  CURRT_OPERN=NULLT THENCONTINUE 
         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 
      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
                                        ! COMPARISONS ARE IMPOSSIBLE TO OPTIMISE
                                        ! ON CONDITION CODE MACHINES
                                        ! POSSIBLE BUT DIFFICULT ON TRUE FLAG MCS
      IF  OPERN=COMP OR  OPERN=DCOMP OR  OPERN=SCOMP OR  OPERN=SDCMP C 
         THEN  RETURN 
      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; ! PRO TEM
         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  C 
            OPND1_D=OPND2_D AND  OPND1_XTRA=OPND2_XTRA AND  C 
            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