-- file: PeepholeQ.mesa, edited by Sweet on March 19, 1979 10:53 AM DIRECTORY Code: FROM "code" USING [CodeNotImplemented, CodePassInconsistency, codeptr, dStar], P5U: FROM "p5u" USING [DeleteCell], CodeDefs: FROM "codedefs" USING [CCIndex, CCNull, CodeCCIndex, JumpCCIndex, JumpType, NULLfileindex], ComData: FROM "comdata" USING [switches], FOpCodes: FROM "fopcodes" USING [qADD, qAND, qBCAST, qBCASTL, qBLT, qBLTC, qBLTCL, qBLTL, qDADD, qDBL, qDEC, qDESCB, qDESCBS, qDST, qDUP, qDWDC, qEFC, qEXCH, qFDESCBS, qGADRB, qINC, qIWDC, qKFCB, qLADRB, qLFC, qLG, qLGD, qLI, qLINKB, qLINT, qLL, qLLD, qLLK, qLP, qLST, qLSTF, qME, qMEL, qMRE, qMREL, qMUL, qMXD, qMXDL, qMXW, qMXWL, qNEG, qNILCK, qNILCKL, qNOOP, qNOTIFY, qNOTIFYL, qOR, qPL, qPOP, qPORTI, qPORTO, qPS, qPSD, qPSF, qPUSH, qR, qRD, qRDL, qREQUEUE, qREQUEUEL, qRET, qRF, qRFL, qRFS, qRFSL, qRIG, qRIGL, qRIL, qRILF, qRILL, qRL, qRSTR, qRSTRL, qRXG, qRXGL, qRXL, qRXLL, qSDIV, qSFC, qSG, qSGD, qSHIFT, qSL, qSLD, qSUB, qW, qWD, qWDL, qWF, qWFL, qWIG, qWIGL, qWIL, qWILL, qWL, qWS, qWSD, qWSF, qWSTR, qWSTRL, qWXG, qWXGL, qWXL, qWXLL, qXOR], InlineDefs: FROM "inlinedefs" USING [BITAND, BITSHIFT], OpCodeParams: FROM "opcodeparams" USING [BYTE, GlobalHB, HB, LocalBase, LocalHB, LocalPutSlots], P5: FROM "p5" USING [PopEffect, PushEffect, C0, C1, C2, LoadConstant], PeepholeDefs: FROM "peepholedefs" USING [PeepZ, Delete2, Delete3, HalfByteLocal, InitJParametersBC, InitParametersABC, InitParametersBC, InitParametersC, JumpPeepState, LoadInst, MC0, PeepholeUNotify, PeepholeZNotify, PeepState, SetRealInst, SetSourceIndex, SlidePeepState1, SlidePeepState2, UnpackFD], SDDefs: FROM "sddefs" USING [sBLTE, sBLTEC, sBLTECL, sBLTEL, sBYTBLTE, sBYTBLTEC, sBYTBLTECL, sBYTBLTEL, sSignedDiv], Table: FROM "table" USING [Base, Notifier], Tree: FROM "tree" USING [treeType]; PeepholeQ: PROGRAM IMPORTS CPtr: Code, MPtr: ComData, InlineDefs, P5U, P5, PeepholeDefs EXPORTS CodeDefs, P5, PeepholeDefs = BEGIN OPEN PeepholeDefs, OpCodeParams, CodeDefs; -- imported definitions BYTE: TYPE = OpCodeParams.BYTE; qNOOP: BYTE = FOpCodes.qNOOP; cb: Table.Base; -- code base (local copy) RJump: ARRAY JumpType[JumpE..UJumpLE] OF JumpType = [ JumpE, JumpN, JumpG, JumpLE, JumpL, JumpGE, UJumpG, UJumpLE, UJumpL, UJumpGE]; DummyProc: PROCEDURE = BEGIN -- every 2 minutes of compile time helps s: PeepState; js: JumpPeepState; IF FALSE THEN [] ← s; IF FALSE THEN [] ← js; END; PeepholeNotify: PUBLIC Table.Notifier = BEGIN -- called by allocator whenever table area is repacked cb ← base[Tree.treeType]; PeepholeZNotify[base]; PeepholeUNotify[base]; RETURN END; start: CodeCCIndex; PeepHole: PUBLIC PROCEDURE [s: CCIndex] = BEGIN start ← LOOPHOLE[s]; SetRealInst[FALSE]; IF ~(CPtr.dStar OR MPtr.switches['l]) THEN RemoveLongs[]; Peep0[]; Peep1[]; Peep2[]; Peep3[]; Peep4[]; Peep5[]; Peep6[]; Peep7[]; SetRealInst[TRUE]; PeepZ[start]; SetSourceIndex[NULLfileindex]; END; RemoveLongs: PROCEDURE = BEGIN -- remove long instructions OPEN FOpCodes; next: CodeCCIndex; state: PeepState; newinst: BYTE; BEGIN OPEN state; next ← start; UNTIL (c ← next) = CCNull DO next ← LOOPHOLE[cb[c].flink]; newinst ← qNOOP; WITH cb[LOOPHOLE[c,CCIndex]] SELECT FROM code => BEGIN InitParametersC[@state]; SELECT cInst FROM qRL => BEGIN newinst ← qR; GOTO pop0 END; qRDL => BEGIN newinst ← qRD; GOTO pop0 END; qRFL => BEGIN newinst ← qRF; GOTO pop0 END; qWL => BEGIN newinst ← qW; GOTO pop0 END; qWFL => BEGIN newinst ← qWF; GOTO pop0 END; qRFSL => BEGIN newinst ← qRFS; GOTO pop1 END; qRSTRL => BEGIN newinst ← qRSTR; GOTO pop1 END; qWDL => BEGIN newinst ← qWD; GOTO pop0 END; qWSTRL => BEGIN newinst ← qWSTR; GOTO pop1 END; qRXLL => newinst ← qRXL; qWXLL => newinst ← qWXL; qRXGL => newinst ← qRXG; qWXGL => newinst ← qWXG; qRILL => newinst ← qRIL; qWILL => newinst ← qWIL; qRIGL => newinst ← qRIG; qWIGL => newinst ← qWIG; qBLTCL => BEGIN newinst ← qBLTC; GOTO pop0 END; qBLTL => BEGIN newinst ← qBLT; InsertPOP[0]; GOTO pop2 END; qMEL => BEGIN newinst ← qME; GOTO pop0 END; qMREL => BEGIN newinst ← qMRE; InsertPOP[0]; GOTO pop1 END; qMXWL => BEGIN newinst ← qMXW; InsertPOP[1]; GOTO pop2 END; qMXDL => BEGIN newinst ← qMXD; GOTO pop0 END; qNOTIFYL => BEGIN newinst ← qNOTIFY; GOTO pop0 END; qBCASTL => BEGIN newinst ← qBCAST; GOTO pop0 END; qREQUEUEL => BEGIN newinst ← qREQUEUE; InsertPOP[1]; GOTO pop2 END; qKFCB => BEGIN OPEN SDDefs; newp1: WORD; SELECT cP[1] FROM sBLTEL => BEGIN newp1 ← sBLTE; InsertPOP[0] END; sBYTBLTEL => BEGIN newp1 ← sBYTBLTE; InsertPOP[0] END; sBLTECL => newp1 ← sBLTEC; sBYTBLTECL => newp1 ← sBYTBLTEC; ENDCASE => GO TO notspecial; cb[c].parameters[1] ← newp1; GO TO pop2; EXITS notspecial => NULL; END; ENDCASE; EXITS pop0 => InsertPOP[0]; pop1 => InsertPOP[1]; pop2 => InsertPOP[2]; END; ENDCASE; -- of WITH IF newinst # qNOOP THEN cb[c].inst ← newinst; ENDLOOP; END; -- of OPEN RETURN END; BackupCP: PROCEDURE [n: INTEGER] RETURNS [INTEGER] = BEGIN OPEN FOpCodes; -- back up codeptr n stack positions cc: CCIndex ← CPtr.codeptr; neteffect: INTEGER; WHILE (cc ← cb[cc].blink) # CCNull AND n # 0 DO WITH cb[cc] SELECT FROM code => BEGIN IF realinst THEN EXIT; SELECT inst FROM qEFC, qLFC, qSFC, qKFCB, qRET, qPORTO, qPORTI, qLST, qLSTF, qDST => EXIT; ENDCASE; neteffect ← P5.PushEffect[inst] - P5.PopEffect[inst]; IF n-neteffect < 0 THEN EXIT; n ← n - neteffect; END; ENDCASE => EXIT; ENDLOOP; CPtr.codeptr ← cc; RETURN[n] END; InsertPOP: PROCEDURE [n: INTEGER] = BEGIN OPEN FOpCodes; -- insert (or simulate) a POP of the word at tos-n savecodeptr: CCIndex ← CPtr.codeptr; n ← BackupCP[n]; SELECT n FROM 0 => P5.C0[qPOP]; 1 => BEGIN P5.C0[qEXCH]; P5.C0[qPOP] END; 2 => BEGIN P5.C0[qPOP]; P5.C0[qEXCH]; P5.C0[qPUSH]; P5.C0[qEXCH]; P5.C0[qPOP] END; 3 => BEGIN P5.C0[qPOP]; P5.C0[qPOP]; P5.C0[qEXCH]; P5.C0[qPUSH]; P5.C0[qEXCH]; P5.C0[qPUSH]; P5.C0[qEXCH]; P5.C0[qPOP] END; ENDCASE => SIGNAL CPtr.CodePassInconsistency; CPtr.codeptr ← savecodeptr; RETURN END; Peep0: PROCEDURE = BEGIN -- undo doubles OPEN FOpCodes; next: CodeCCIndex; state: PeepState; next ← start; BEGIN OPEN state; UNTIL (c ← next) = CCNull DO next ← LOOPHOLE[cb[c].flink]; WITH cb[LOOPHOLE[c,CCIndex]] SELECT FROM code => BEGIN InitParametersC[@state]; SELECT cInst FROM qLGD => BEGIN inst ← qLG; P5.C1[qLG, cP[1]+1]; END; qLLD => BEGIN inst ← qLL; P5.C1[qLL, cP[1]+1]; END; ENDCASE; END; ENDCASE; -- of WITH ENDLOOP; END; -- of OPEN state RETURN END; Peep1: PROCEDURE = BEGIN -- remove POPs by modifying previous instruction OPEN FOpCodes; next, ci: CCIndex; didsomething: BOOLEAN ← TRUE; WHILE didsomething DO next ← start; didsomething ← FALSE; UNTIL (ci ← next) = CCNull DO next ← cb[ci].flink; WITH cb[ci] SELECT FROM code => IF inst = qPOP AND ~realinst THEN didsomething ← didsomething OR RemoveThisPop[ci]; ENDCASE; ENDLOOP; ENDLOOP; RETURN END; RemoveThisPop: PUBLIC PROCEDURE [ci: CCIndex] RETURNS [didThisTime: BOOLEAN] = BEGIN -- remove POP by modifying previous instruction, if possible OPEN FOpCodes; state: PeepState; didThisTime ← FALSE; WITH cb[ci] SELECT FROM code => BEGIN OPEN state; c ← LOOPHOLE[ci]; InitParametersABC[@state]; SELECT cInst FROM qPOP => IF Popable[bInst] THEN BEGIN P5U.DeleteCell[b]; P5U.DeleteCell[c]; didThisTime ← TRUE; END ELSE SELECT bInst FROM qR, qRF, qRXL, qNEG, qDESCBS, qINC, qDEC => BEGIN P5U.DeleteCell[b]; [] ← RemoveThisPop[c]; -- the blink may be popable now -- above is unnecessary if called from Peep1 -- but useful if called from jump elimination didThisTime ← TRUE; END; qDADD => IF Popable[aInst] THEN BEGIN Delete2[a,b]; InsertPOP[1]; MC0[qADD, bMin]; P5U.DeleteCell[c]; didThisTime ← TRUE; END; qRD => BEGIN cb[b].inst ← qR; P5U.DeleteCell[c]; didThisTime ← TRUE; END; qIWDC, qDWDC => BEGIN CommuteCells[b,c]; didThisTime ← TRUE; END; qNILCKL => BEGIN cb[b].inst ← qNILCK; CommuteCells[b,c]; -- no recursive call since jump elimination needs code -- to go to nothing. didThisTime ← TRUE; END; ENDCASE; ENDCASE; END; ENDCASE; -- of WITH END; Popable: PROCEDURE [inst: BYTE] RETURNS [BOOLEAN] = BEGIN OPEN FOpCodes; RETURN[inst#qNOOP AND (P5.PopEffect[inst]=0 AND P5.PushEffect[inst]=1 OR inst = qLP OR inst = qDUP)] END; Peep2: PROCEDURE = BEGIN -- expand families OPEN FOpCodes; next, ci: CCIndex; state: PeepState; canSlide: BOOLEAN ← FALSE; next ← start; BEGIN OPEN state; UNTIL (ci ← next) = CCNull DO next ← cb[ci].flink; WITH cb[ci] SELECT FROM code => BEGIN IF canSlide THEN SlidePeepState2[@state, LOOPHOLE[ci]] ELSE BEGIN c ← LOOPHOLE[ci]; InitParametersABC[@state]; END; canSlide ← FALSE; SELECT cInst FROM -- expand out-of-range families qRIG => IF cP[1] ~IN GlobalHB OR cP[2] ~IN HB THEN BEGIN P5.C1[qLG, cP[1]]; P5.C1[qR, cP[2]]; P5U.DeleteCell[c]; END; qRIL => IF cP[1] ~IN LocalHB OR cP[2] ~IN HB THEN BEGIN P5.C1[qLL, cP[1]]; P5.C1[qR, cP[2]]; P5U.DeleteCell[c]; END; qRXL => IF cP[1] ~IN LocalHB OR cP[2] ~IN HB THEN BEGIN P5.C1[qLL, cP[1]]; MC0[qADD, cMin]; P5.C1[qR, cP[2]]; P5U.DeleteCell[c]; END; qWXL => IF cP[1] ~IN LocalHB OR cP[2] ~IN HB THEN BEGIN P5.C1[qLL, cP[1]]; P5.C0[qADD]; P5.C1[qW, cP[2]]; P5U.DeleteCell[c]; END; qWIL => IF cP[1] ~IN LocalHB OR cP[2] ~IN HB THEN BEGIN P5.C1[qLL, cP[1]]; P5.C1[qW, cP[2]]; P5U.DeleteCell[c]; END; qRXG => IF TRUE THEN BEGIN P5.C1[qLG, cP[1]]; MC0[qADD, cMin]; P5.C1[qR, cP[2]]; P5U.DeleteCell[c]; END; qWXG => IF TRUE THEN BEGIN P5.C1[qLG, cP[1]]; P5.C0[qADD]; P5.C1[qW, cP[2]]; P5U.DeleteCell[c]; END; qWIG => IF TRUE THEN BEGIN P5.C1[qLG, cP[1]]; P5.C1[qW, cP[2]]; P5U.DeleteCell[c]; END; qRIGL => IF cP[1] ~IN GlobalHB OR cP[2] ~IN HB THEN BEGIN P5.C1[qLGD, cP[1]]; P5.C1[qRL, cP[2]]; P5U.DeleteCell[c]; END; qRILL => IF cP[1] ~IN LocalHB OR cP[2] ~IN HB THEN BEGIN P5.C1[qLLD, cP[1]]; P5.C1[qRL, cP[2]]; P5U.DeleteCell[c]; END; qRXLL => IF cP[1] ~IN LocalHB OR cP[2] ~IN HB THEN BEGIN P5.LoadConstant[0]; P5.C1[qLLD, cP[1]]; P5.C0[qDADD]; P5.C1[qRL, cP[2]]; P5U.DeleteCell[c]; END; qWXLL => IF cP[1] ~IN LocalHB OR cP[2] ~IN HB THEN BEGIN P5.LoadConstant[0]; P5.C1[qLLD, cP[1]]; P5.C0[qDADD]; P5.C1[qWL, cP[2]]; P5U.DeleteCell[c]; END; qWILL => IF cP[1] ~IN LocalHB OR cP[2] ~IN HB THEN BEGIN P5.C1[qLLD, cP[1]]; P5.C1[qWL, cP[2]]; P5U.DeleteCell[c]; END; qRXGL => IF cP[1] ~IN GlobalHB OR cP[2] ~IN HB THEN BEGIN P5.LoadConstant[0]; P5.C1[qLGD, cP[1]]; P5.C0[qDADD]; P5.C1[qRL, cP[2]]; P5U.DeleteCell[c]; END; qWXGL => IF cP[1] ~IN GlobalHB OR cP[2] ~IN HB THEN BEGIN P5.LoadConstant[0]; P5.C1[qLGD, cP[1]]; P5.C0[qDADD]; P5.C1[qWL, cP[2]]; P5U.DeleteCell[c]; END; qWIGL => IF cP[1] ~IN GlobalHB OR cP[2] ~IN HB THEN BEGIN P5.C1[qLGD, cP[1]]; P5.C1[qWL, cP[2]]; P5U.DeleteCell[c]; END; qRILF => IF TRUE THEN BEGIN P5.C1[qLL, cP[1]]; P5.C2[qRF, cP[2], cP[3]]; P5U.DeleteCell[c]; END; qEFC, qLLK => IF cP[1] ~IN BYTE THEN SIGNAL CPtr.CodeNotImplemented; qLINKB => IF cP[1] ~IN BYTE THEN BEGIN cb[c].parameters[1] ← 377B; P5.C1[qLL, LocalBase]; P5.LoadConstant[cP[1]-377B]; P5.C0[qSUB]; P5.C1[qSL, LocalBase]; END; qDESCBS, qDESCB, qFDESCBS => BEGIN IF cP[1]/2 ~IN BYTE OR cP[1] MOD 2 = 0 THEN SIGNAL CPtr.CodeNotImplemented; parameters[1] ← cP[1]/2; IF cInst = qFDESCBS THEN BEGIN inst ← qDESCBS; P5.C0[qSFC]; END; END; qSDIV => BEGIN P5.C1[qKFCB, SDDefs.sSignedDiv]; P5U.DeleteCell[c]; END; qDEC => IF cMin THEN BEGIN P5.LoadConstant[0-1]; MC0[qADD, TRUE]; P5U.DeleteCell[c] END ELSE BEGIN P5.LoadConstant[1]; P5.C0[qSUB]; P5U.DeleteCell[c] END; qLINT => BEGIN P5.C0[qDUP]; P5.LoadConstant[0-15]; P5.C0[qSHIFT]; P5.C0[qNEG]; P5U.DeleteCell[c]; END; qGADRB, qLADRB => IF cP[1] ~IN BYTE THEN BEGIN parameters[1] ← LAST[BYTE]; P5.LoadConstant[cP[1]-LAST[BYTE]]; MC0[qADD, cMin]; END; qWS, qPS, qWSF, qPSF, qWSD, qPSD => IF cP[1] ~IN BYTE THEN SIGNAL CPtr.CodePassInconsistency; -- discover family members from sequences qR => IF cP[1] IN HB THEN SELECT bInst FROM qADD => IF HalfByteLocal[a] THEN BEGIN P5.C2[qRXL, aP[1], cP[1]]; Delete3[a,b,c]; END; qLL => IF bP[1] IN LocalHB THEN BEGIN P5.C2[qRIL, bP[1], cP[1]]; Delete2[b,c]; END; qLG => IF bP[1] IN GlobalHB THEN BEGIN P5.C2[qRIG, bP[1], cP[1]]; Delete2[b,c]; END; ENDCASE; qW => IF cP[1] IN HB THEN SELECT bInst FROM qADD => IF HalfByteLocal[a] THEN BEGIN P5.C2[qWXL, aP[1], cP[1]]; Delete3[a,b,c]; END; qLL => IF bP[1] IN LocalHB THEN BEGIN P5.C2[qWIL, bP[1], cP[1]]; Delete2[b,c]; END; ENDCASE; ENDCASE => canSlide ← TRUE; END; ENDCASE => canSlide ← FALSE; -- of WITH ENDLOOP; END; -- of OPEN state RETURN END; Peep3: PROCEDURE = BEGIN -- sprinkle DUPs OPEN FOpCodes; next, ci: CCIndex; state: PeepState; canSlide: BOOLEAN ← FALSE; next ← start; BEGIN OPEN state; UNTIL (ci ← next) = CCNull DO next ← cb[ci].flink; WITH cb[ci] SELECT FROM code => BEGIN IF canSlide THEN SlidePeepState2[@state, LOOPHOLE[ci]] ELSE BEGIN c ← LOOPHOLE[ci]; InitParametersABC[@state]; END; canSlide ← FALSE; SELECT cInst FROM -- replace load,load with load,DUP qLL, qLG, qLI => IF bInst = cInst AND cP[1] = bP[1] THEN BEGIN P5.C0[qDUP]; P5U.DeleteCell[c] END; qRIL, qRIG, qRILL, qRIGL => IF bInst = cInst AND cP[1] = bP[1] AND cP[2] = bP[2] THEN BEGIN P5.C0[qDUP]; P5U.DeleteCell[c] END; ENDCASE => canSlide ← TRUE; END; ENDCASE => canSlide ← FALSE; -- of WITH ENDLOOP; END; -- of OPEN state RETURN END; Peep4: PROCEDURE = BEGIN -- PUTs and PUSHs, RF and WF to RSTR and WSTR OPEN FOpCodes; next, ci: CCIndex; state: PeepState; pos, size: [0..16); canSlide: BOOLEAN ← FALSE; next ← start; BEGIN OPEN state; UNTIL (ci ← next) = CCNull DO next ← cb[ci].flink; WITH cb[ci] SELECT FROM code => BEGIN IF canSlide THEN SlidePeepState2[@state, LOOPHOLE[ci]] ELSE BEGIN c ← LOOPHOLE[ci]; InitParametersABC[@state]; END; canSlide ← FALSE; SELECT cInst FROM qLL => IF bInst = qSL AND cP[1] = bP[1] THEN IF cP[1] IN LocalPutSlots THEN BEGIN cb[b].inst ← qPL; P5U.DeleteCell[c]; END ELSE BEGIN P5.C0[qPUSH]; P5U.DeleteCell[c]; END ELSE GO TO Slide; qPUSH => IF bInst = qSL AND bP[1] IN LocalPutSlots THEN BEGIN cb[b].inst ← qPL; P5U.DeleteCell[c]; END ELSE GO TO Slide; qLG => IF bInst = qSG AND cP[1] = bP[1] THEN BEGIN P5.C0[qPUSH]; P5U.DeleteCell[c]; END ELSE GO TO Slide; qRIL => IF bInst = qWIL AND cP[1] = bP[1] AND cP[2] = bP[2] THEN BEGIN P5.C0[qPUSH]; P5U.DeleteCell[c] END ELSE GO TO Slide; qRILL => IF bInst = qWILL AND cP[1] = bP[1] AND cP[2] = bP[2] THEN BEGIN P5.C0[qPUSH]; P5U.DeleteCell[c] END ELSE GO TO Slide; qRIGL => IF bInst = qWIGL AND cP[1] = bP[1] AND cP[2] = bP[2] THEN BEGIN P5.C0[qPUSH]; P5U.DeleteCell[c] END ELSE GO TO Slide; qRF, qWF, qRFL, qWFL => BEGIN [pos, size] ← UnpackFD[LOOPHOLE[cP[2]]]; IF size = 8 AND cP[1] <= LAST[BYTE]/2 THEN SELECT pos FROM 0, 8 => BEGIN P5.LoadConstant[0]; P5.C1[(SELECT cInst FROM qRF => qRSTR, qWF => qWSTR, qRFL => qRSTRL, ENDCASE => qWSTRL), cP[1]*2+pos/8]; P5U.DeleteCell[c]; END; ENDCASE => GO TO Slide ELSE GO TO Slide; END; ENDCASE => GO TO Slide; EXITS Slide => canSlide ← TRUE; END; ENDCASE => canSlide ← FALSE; -- of WITH ENDLOOP; END; -- of OPEN state RETURN END; NonWS: ARRAY [FOpCodes.qWS..FOpCodes.qWSD] OF BYTE = [FOpCodes.qW, FOpCodes.qWF, FOpCodes.qWD]; Peep5: PROCEDURE = BEGIN -- put doubles back, eliminate EXCH preceding commutative operator OPEN FOpCodes; next, ci: CCIndex; state: PeepState; canSlide: BOOLEAN ← FALSE; next ← start; BEGIN OPEN state; UNTIL (ci ← next) = CCNull DO next ← cb[ci].flink; WITH cc:cb[ci] SELECT FROM code => BEGIN IF canSlide THEN SlidePeepState2[@state, LOOPHOLE[ci]] ELSE BEGIN c ← LOOPHOLE[ci]; InitParametersABC[@state]; END; canSlide ← FALSE; SELECT cInst FROM qLL => IF bInst = qLL AND cP[1] = bP[1]+1 THEN BEGIN cb[b].inst ← qLLD; P5U.DeleteCell[c]; END ELSE GO TO Slide; qSL => IF bInst = qSL AND cP[1] = bP[1]-1 THEN BEGIN cb[c].inst ← qSLD; P5U.DeleteCell[b]; END ELSE GO TO Slide; qLG => IF bInst = qLG AND cP[1] = bP[1]+1 THEN BEGIN cb[b].inst ← qLGD; P5U.DeleteCell[c]; END ELSE GO TO Slide; qSG => IF bInst = qSG AND cP[1] = bP[1]-1 THEN BEGIN cb[c].inst ← qSGD; P5U.DeleteCell[b]; END ELSE GO TO Slide; qADD, qMUL, qAND, qOR, qXOR => IF bInst = qEXCH THEN P5U.DeleteCell[b] ELSE GO TO Slide; qWS, qWSF, qWSD => IF bInst = qEXCH THEN BEGIN P5U.DeleteCell[b]; cc.inst ← NonWS[cInst]; END ELSE GO TO Slide; qEXCH => IF bInst = qEXCH THEN Delete2[b,c] ELSE IF LoadInst[b] AND LoadInst[a] THEN BEGIN P5U.DeleteCell[c]; CommuteCells[a,b]; cb[a].minimalStack ← bMin; cb[b].minimalStack ← aMin; END ELSE GO TO Slide; ENDCASE => GO TO Slide; EXITS Slide => canSlide ← TRUE; END; jump => BEGIN canSlide ← FALSE; IF cc.jtype IN [JumpE..UJumpLE] THEN WITH cb[cc.blink] SELECT FROM code => IF ~realinst AND inst = qEXCH AND ~PushFollows[LOOPHOLE[ci,JumpCCIndex]] THEN BEGIN P5U.DeleteCell[cc.blink]; cc.jtype ← RJump[cc.jtype]; END; ENDCASE; END; ENDCASE => canSlide ← FALSE; -- of WITH ENDLOOP; END; -- of OPEN state RETURN END; PushFollows: PROCEDURE [c: JumpCCIndex] RETURNS [BOOLEAN] = BEGIN -- c is conditional jump; TRUE if PUSH follows on either branch next: CCIndex; FOR next ← cb[c].flink, cb[next].flink WHILE next # CCNull DO WITH cb[next] SELECT FROM code => IF ~realinst AND inst = FOpCodes.qPUSH THEN RETURN[TRUE] ELSE EXIT; label => NULL; ENDCASE => EXIT; ENDLOOP; IF (next←cb[cb[c].destlabel].flink) # CCNull THEN WITH cb[next] SELECT FROM code => IF ~realinst AND inst = FOpCodes.qPUSH THEN RETURN[TRUE]; ENDCASE; RETURN[FALSE] END; CommuteCells: PROCEDURE [a, b: CCIndex] = BEGIN prev, next: CCIndex; prev ← cb[a].blink; -- never Null next ← cb[b].flink; cb[prev].flink ← b; cb[b].blink ← prev; cb[b].flink ← a; cb[a].blink ← b; cb[a].flink ← next; IF next # CCNull THEN cb[next].blink ← a; RETURN END; Peep6: PROCEDURE = BEGIN -- store double/load double, INC and DEC, MUL to SHIFT etc OPEN FOpCodes; next, ci: CCIndex; canSlide: BOOLEAN ← FALSE; state: PeepState; negate, powerof2: BOOLEAN; log: CARDINAL; d2: PROCEDURE = BEGIN Delete2[state.b, state.c]; IF negate THEN P5.C0[qNEG]; RETURN END; next ← start; BEGIN OPEN state; UNTIL (ci ← next) = CCNull DO next ← cb[ci].flink; WITH cb[ci] SELECT FROM code => BEGIN IF canSlide THEN SlidePeepState1[@state, LOOPHOLE[ci]] ELSE BEGIN c ← LOOPHOLE[ci]; InitParametersBC[@state]; END; canSlide ← FALSE; SELECT cInst FROM qLLD => IF bInst = qSLD AND cP[1] = bP[1] THEN IF cP[1] IN LocalPutSlots THEN BEGIN P5.C1[qSL, cP[1]+1]; P5.C1[qPL, cP[1]]; P5.C0[qPUSH]; Delete2[b,c]; END ELSE BEGIN P5.C0[qPUSH]; P5.C0[qPUSH]; P5U.DeleteCell[c] END ELSE GO TO Slide; qLGD => IF bInst = qSGD AND cP[1] = bP[1] THEN BEGIN P5.C0[qPUSH]; P5.C0[qPUSH]; P5U.DeleteCell[c] END ELSE GO TO Slide; qADD, qSUB => IF bInst = qLI THEN BEGIN SELECT LOOPHOLE[bP[1], INTEGER] FROM 0 => Delete2[b,c]; 1 => IF cInst = qADD THEN BEGIN cb[c].inst ← qINC; P5U.DeleteCell[b]; END; -1 => IF cInst = qSUB THEN BEGIN cb[c].inst ← qINC; P5U.DeleteCell[b]; END; ENDCASE => GO TO Slide; END ELSE IF bInst = qNEG THEN BEGIN cb[c].inst ← IF cInst = qADD THEN qSUB ELSE qADD; P5U.DeleteCell[b]; END ELSE GO TO Slide; qSHIFT => IF bInst = qLI THEN SELECT bP[1] FROM 1 => BEGIN cb[c].inst ← qDBL; P5U.DeleteCell[b] END; 0 => Delete2[b,c]; ENDCASE => GO TO Slide ELSE GO TO Slide; qMUL => IF bInst = qLI THEN BEGIN negate ← FALSE; IF LOOPHOLE[bP[1], INTEGER] < 0 THEN BEGIN negate ← TRUE; bP[1] ← -LOOPHOLE[bP[1],INTEGER]; END; SELECT bP[1] FROM 1 => d2[]; 2 => BEGIN P5.C0[qDBL]; d2[]; END; 3 => BEGIN P5.C0[qDUP]; P5.C0[qDBL]; MC0[qADD, cMin]; d2[]; END; 4 => BEGIN P5.C0[qDBL]; P5.C0[qDBL]; d2[]; END; 5 => BEGIN P5.C0[qDUP]; P5.C0[qDBL]; P5.C0[qDBL]; MC0[qADD, cMin]; d2[]; END; 6 => BEGIN P5.C0[qDBL]; P5.C0[qDUP]; P5.C0[qDBL]; MC0[qADD, cMin]; d2[]; END; ENDCASE => BEGIN [powerof2, log] ← Log2[LOOPHOLE[bP[1]]]; IF powerof2 THEN BEGIN P5.LoadConstant[log]; P5.C0[qSHIFT]; d2[]; END ELSE GO TO Slide; END; END; ENDCASE => GO TO Slide; EXITS Slide => canSlide ← TRUE; END; ENDCASE => canSlide ← FALSE; -- of WITH ENDLOOP; END; -- of OPEN state RETURN END; Log2: PROCEDURE [i: INTEGER] RETURNS [BOOLEAN, CARDINAL] = BEGIN OPEN InlineDefs; shift: CARDINAL; IF i = 0 THEN RETURN [FALSE, 0]; i ← ABS[i]; IF BITAND[i, i-1] # 0 THEN RETURN [FALSE, 0]; FOR shift IN [0..16) DO IF BITAND[i,1] = 1 THEN RETURN[TRUE, shift]; i ← BITSHIFT[i, -1]; ENDLOOP; ERROR; -- can't be reached END; Peep7: PROCEDURE = BEGIN -- find special jumps OPEN FOpCodes; next: JumpCCIndex; jstate: JumpPeepState; next ← LOOPHOLE[start]; BEGIN OPEN jstate; UNTIL (c ← next) = CCNull DO next ← LOOPHOLE[cb[c].flink]; WITH cb[LOOPHOLE[c,CCIndex]] SELECT FROM jump => BEGIN InitJParametersBC[@jstate]; CPtr.codeptr ← c; SELECT jtype FROM JumpE => IF bInst = qLI THEN IF bP[1] = 0 THEN BEGIN jtype ← ZJumpE; P5U.DeleteCell[b] END; JumpN => IF bInst = qLI THEN IF bP[1] = 0 THEN BEGIN jtype ← ZJumpN; P5U.DeleteCell[b] END; ENDCASE; END; ENDCASE; -- of WITH ENDLOOP; END; -- of OPEN state RETURN END; END...