-- file: PeepholeQ.mesa -- last edited by Sweet on August 22, 1980 4:12 PM -- last edited by Satterthwaite on May 25, 1982 12:15 pm DIRECTORY Alloc: TYPE USING [Notifier], Code: TYPE USING [CodeNotImplemented, CodePassInconsistency, codeptr], P5U: TYPE USING [DeleteCell], CodeDefs: TYPE USING [ Base, CCIndex, CCNull, CodeCCIndex, codeType, JumpCCIndex, JumpType], FOpCodes: TYPE USING [ qADD, qAMUL, qAND, qDADD, qDBL, qDEC, qDESCB, qDESCBS, qDIV, qDST, qDUP, qDWDC, qEFC, qEXCH, qFDESCBS, qGADRB, qINC, qIWDC, qKFCB, qLADRB, qLFC, qLG, qLGD, qLI, qLINKB, qLINT, qLL, qLLD, qLLK, qLST, qLSTF, qMUL, qNEG, qNOOP, qOR, qPL, qPOP, qPORTI, qPORTO, qPS, qPSD, qPSF, qPUSH, qR, qRD, qRET, qRF, qRFL, qRFS, qRIG, qRIGL, qRIL, qRILF, qRILL, qRL, qRSTR, qRSTRL, qRXG, qRXGL, qRXL, qRXLL, qSDIV, qSFC, qSG, qSGD, qSHIFT, qSL, qSLD, qSUB, qW, qWD, qWF, qWFL, qWIG, qWIGL, qWIL, qWILL, qWL, qWS, qWSD, qWSF, qWSTR, qWSTRL, qWXG, qWXGL, qWXL, qWXLL, qXOR], Inline: TYPE USING [BITAND, BITSHIFT], OpCodeParams: TYPE USING [Byte, GlobalHB, HB, LocalBase, LocalHB, LocalPutSlots], P5: TYPE USING [PopEffect, PushEffect, C0, C1, C2, LoadConstant], PeepholeDefs: TYPE USING [ PeepZ, Delete2, Delete3, HalfByteGlobal, HalfByteLocal, InitJParametersBC, InitParameters, JumpPeepState, LoadInst, MC0, NextInteresting, PeepholeUNotify, PeepholeZNotify, PeepState, PrevInteresting, SetRealInst, SlidePeepState1, SlidePeepState2, UnpackFD], SDDefs: TYPE USING [sSignedDiv]; PeepholeQ: PROGRAM IMPORTS CPtr: Code, Inline, P5U, P5, PeepholeDefs EXPORTS CodeDefs, P5, PeepholeDefs = BEGIN OPEN PeepholeDefs, OpCodeParams, CodeDefs; -- imported definitions Byte: TYPE = OpCodeParams.Byte; qNOOP: Byte = FOpCodes.qNOOP; cb: CodeDefs.Base; -- code base (local copy) RJump: ARRAY JumpType[JumpE..UJumpLE] OF JumpType = [ JumpE, JumpN, JumpG, JumpLE, JumpL, JumpGE, UJumpG, UJumpLE, UJumpL, UJumpGE]; DummyProc: PROC = BEGIN -- every 2 minutes of compile time helps s: PeepState; js: JumpPeepState; IF FALSE THEN [] ← s; IF FALSE THEN [] ← js; END; PeepholeNotify: PUBLIC Alloc.Notifier = BEGIN -- called by allocator whenever table area is repacked cb ← base[codeType]; PeepholeZNotify[base]; PeepholeUNotify[base]; END; start: CodeCCIndex; PeepHole: PUBLIC PROC [s: CCIndex] = BEGIN start ← LOOPHOLE[s]; SetRealInst[FALSE]; Peep0[]; Peep1[]; Peep2[]; Peep3[]; Peep4[]; Peep5[]; Peep6[]; Peep7[]; SetRealInst[TRUE]; PeepZ[start]; END; BackupCP: PROC [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 THEN EXIT; n ← n - netEffect; END; other => IF otag = table THEN EXIT; ENDCASE => EXIT; ENDLOOP; CPtr.codeptr ← cc; RETURN [n] END; InsertPOP: PROC [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 => {P5.C0[qEXCH]; P5.C0[qPOP]}; 2 => {P5.C0[qPOP]; P5.C0[qEXCH]; P5.C0[qPUSH]; P5.C0[qEXCH]; P5.C0[qPOP]}; 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; END; Peep0: PROC = BEGIN -- undo doubles OPEN FOpCodes; ci: CCIndex; state: PeepState; next: CCIndex ← start; UNTIL (ci ← next) = CCNull DO next ← NextInteresting[ci]; WITH cb[ci] SELECT FROM code => BEGIN OPEN state; InitParameters[@state, LOOPHOLE[ci], c]; SELECT cInst FROM qLGD => {inst ← qLG; P5.C1[qLG, cP[1]+1]}; qLLD => {inst ← qLL; P5.C1[qLL, cP[1]+1]}; ENDCASE; END; -- of OPEN state ENDCASE; -- of WITH ENDLOOP; END; Peep1: PROC = BEGIN -- remove POPs by modifying previous instruction OPEN FOpCodes; next, ci: CCIndex; changed: BOOLEAN ← TRUE; WHILE changed DO next ← start; changed ← FALSE; UNTIL (ci ← next) = CCNull DO next ← NextInteresting[ci]; WITH cb[ci] SELECT FROM code => IF inst = qPOP AND ~realinst THEN changed ← changed OR RemoveThisPop[ci]; ENDCASE; ENDLOOP; ENDLOOP; END; RemoveThisPop: PUBLIC PROC [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; InitParameters[@state, LOOPHOLE[ci], abc]; SELECT cInst FROM qPOP => IF Popable[bInst] THEN {P5U.DeleteCell[b]; P5U.DeleteCell[c]; didThisTime ← TRUE} 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; qRSTR, qADD, qSUB, qMUL, qAMUL, qDIV, qSDIV, qAND, qOR, qXOR, qSHIFT, qRFS, qRL, qRFL => BEGIN np: CCIndex; P5U.DeleteCell[b]; CPtr.codeptr ← cb[c].blink; P5.C0[qPOP]; np ← CPtr.codeptr; [] ← RemoveThisPop[np]; [] ← RemoveThisPop[c]; END; qDADD => IF Popable[aInst] THEN BEGIN Delete2[a,b]; InsertPOP[1]; MC0[qADD, bMin]; P5U.DeleteCell[c]; didThisTime ← TRUE; END; qRD => {cb[b].inst ← qR; P5U.DeleteCell[c]; didThisTime ← TRUE}; qIWDC, qDWDC => {CommuteCells[b,c]; didThisTime ← TRUE}; qEXCH => IF IsLoad[aInst] THEN BEGIN Delete2[b, c]; CPtr.codeptr ← cb[a].blink; P5.C0[qPOP]; [] ← RemoveThisPop[CPtr.codeptr]; didThisTime ← TRUE; END; ENDCASE; ENDCASE; END; ENDCASE; -- of WITH END; Popable: PROC [inst: Byte] RETURNS [BOOLEAN] = BEGIN RETURN [inst#qNOOP AND (P5.PopEffect[inst]=0 AND P5.PushEffect[inst]=1 OR inst = FOpCodes.qDUP)] END; IsLoad: PROC [inst: Byte] RETURNS [BOOLEAN] = BEGIN RETURN [inst#qNOOP AND inst # FOpCodes.qPUSH AND (P5.PopEffect[inst]=0 AND P5.PushEffect[inst]=1)] END; Peep2: PROC = BEGIN -- expand families OPEN FOpCodes; ci: CCIndex; next: CCIndex ← start; state: PeepState; canSlide: BOOLEAN ← FALSE; UNTIL (ci ← next) = CCNull DO next ← NextInteresting[ci]; WITH cb[ci] SELECT FROM code => BEGIN OPEN state; IF canSlide THEN SlidePeepState2[@state, LOOPHOLE[ci]] ELSE InitParameters[@state, LOOPHOLE[ci], abc]; canSlide ← FALSE; SELECT cInst FROM -- expand out-of-range families qEFC, qLLK => BEGIN IF cP[1] NOT IN Byte THEN SIGNAL CPtr.CodeNotImplemented; canSlide ← TRUE; END; qLINKB => IF cP[1] IN Byte THEN canSlide ← TRUE ELSE 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 parameters[1] ← cP[1]*2; IF cInst = qFDESCBS THEN {inst ← qDESCBS; P5.C0[qSFC]}; END; qSDIV => {P5.C1[qKFCB, SDDefs.sSignedDiv]; P5U.DeleteCell[c]}; qDEC => IF cMin THEN {P5.LoadConstant[0-1]; MC0[qADD, TRUE]; P5U.DeleteCell[c]} ELSE {P5.LoadConstant[1]; P5.C0[qSUB]; P5U.DeleteCell[c]}; 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 canSlide ← TRUE ELSE BEGIN parameters[1] ← LAST[Byte]; P5.LoadConstant[cP[1]-LAST[Byte]]; P5.C0[qADD]; END; qWS, qPS, qWSF, qPSF, qWSD, qPSD => BEGIN IF cP[1] NOT IN Byte THEN SIGNAL CPtr.CodePassInconsistency; canSlide ← TRUE; END; -- discover family members from sequences qR => IF cP[1] IN HB THEN SELECT bInst FROM qADD => IF HalfByteLocal[a] THEN {P5.C2[qRXL, aP[1], cP[1]]; Delete3[a,b,c]} ELSE canSlide ← TRUE; qLL => IF bP[1] IN LocalHB THEN {P5.C2[qRIL, bP[1], cP[1]]; Delete2[b,c]} ELSE canSlide ← TRUE; qLG => IF bP[1] IN GlobalHB THEN {P5.C2[qRIG, bP[1], cP[1]]; Delete2[b,c]} ELSE canSlide ← TRUE; ENDCASE => canSlide ← TRUE ELSE canSlide ← TRUE; qW => IF cP[1] IN HB THEN SELECT bInst FROM qADD => IF HalfByteLocal[a] THEN {P5.C2[qWXL, aP[1], cP[1]]; Delete3[a,b,c]} ELSE canSlide ← TRUE; qLL => IF bP[1] IN LocalHB THEN {P5.C2[qWIL, bP[1], cP[1]]; Delete2[b,c]} ELSE canSlide ← TRUE; ENDCASE => canSlide ← TRUE ELSE canSlide ← TRUE; qRL => IF cP[1] IN HB THEN SELECT bInst FROM qADD => IF aInst = qLI AND aP[1] = 0 THEN BEGIN aa: CCIndex = PrevInteresting[a]; IF aa # CCNull THEN WITH cc: cb[aa] SELECT FROM code => IF HalfByteLocal[LOOPHOLE[aa]] THEN BEGIN P5.C2[qRXLL, cc.parameters[1], cP[1]]; Delete3[a,b,c]; P5U.DeleteCell[aa]; END ELSE IF HalfByteGlobal[LOOPHOLE[aa]] THEN BEGIN P5.C2[qRXGL, cc.parameters[1], cP[1]]; Delete3[a,b,c]; P5U.DeleteCell[aa]; END ELSE canSlide ← TRUE; ENDCASE ELSE canSlide ← TRUE; END ELSE canSlide ← TRUE; qLL => IF aInst = qLL AND aP[1] IN LocalHB AND bP[1] = aP[1]+1 THEN {P5.C2[qRILL, aP[1], cP[1]]; Delete3[a,b,c]} ELSE canSlide ← TRUE; qLG => IF aInst = qLL AND aP[1] IN GlobalHB AND bP[1] = aP[1]+1 THEN {P5.C2[qRIGL, aP[1], cP[1]]; Delete3[a,b,c]} ELSE canSlide ← TRUE; ENDCASE => canSlide ← TRUE ELSE canSlide ← TRUE; qWL => IF cP[1] IN HB THEN SELECT bInst FROM qADD => IF aInst = qLI AND aP[1] = 0 THEN BEGIN aa: CCIndex = PrevInteresting[a]; IF aa # CCNull THEN WITH cc: cb[aa] SELECT FROM code => IF HalfByteLocal[LOOPHOLE[aa]] THEN BEGIN P5.C2[qWXLL, cc.parameters[1], cP[1]]; Delete3[a,b,c]; P5U.DeleteCell[aa]; END ELSE IF HalfByteGlobal[LOOPHOLE[aa]] THEN BEGIN P5.C2[qWXGL, cc.parameters[1], cP[1]]; Delete3[a,b,c]; P5U.DeleteCell[aa]; END ELSE canSlide ← TRUE; ENDCASE ELSE canSlide ← TRUE; END ELSE canSlide ← TRUE; qLL => IF aInst = qLL AND aP[1] IN LocalHB AND bP[1] = aP[1]+1 THEN {P5.C2[qWILL, aP[1], cP[1]]; Delete3[a,b,c]} ELSE canSlide ← TRUE; qLG => IF aInst = qLL AND aP[1] IN GlobalHB AND bP[1] = aP[1]+1 THEN {P5.C2[qWIGL, aP[1], cP[1]]; Delete3[a,b,c]} ELSE canSlide ← TRUE; ENDCASE => canSlide ← TRUE ELSE canSlide ← TRUE; 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 {P5.C1[qLG, cP[1]]; P5.C1[qW, cP[2]]; P5U.DeleteCell[c]}; qRILF => IF TRUE THEN BEGIN P5.C1[qLL, cP[1]]; P5.C2[qRF, cP[2], cP[3]]; P5U.DeleteCell[c]; END; ENDCASE => canSlide ← TRUE; END; -- of OPEN state ENDCASE => canSlide ← FALSE; -- of WITH ENDLOOP; END; Peep3: PROC = BEGIN -- sprinkle DUPs OPEN FOpCodes; ci: CCIndex; next: CCIndex ← start; state: PeepState; canSlide: BOOLEAN ← FALSE; UNTIL (ci ← next) = CCNull DO next ← NextInteresting[ci]; WITH cb[ci] SELECT FROM code => BEGIN OPEN state; IF canSlide THEN SlidePeepState2[@state, LOOPHOLE[ci]] ELSE InitParameters[@state, LOOPHOLE[ci], abc]; canSlide ← TRUE; IF bInst = cInst THEN -- replace load,load with load,DUP SELECT cInst FROM qLL, qLG, qLI => IF cP[1] = bP[1] THEN {P5.C0[qDUP]; P5U.DeleteCell[c]; canSlide ← FALSE}; qRIL, qRIG, qRILL, qRIGL => IF cP[1] = bP[1] AND cP[2] = bP[2] THEN {P5.C0[qDUP]; P5U.DeleteCell[c]; canSlide ← FALSE}; ENDCASE; END; -- of OPEN state ENDCASE => canSlide ← FALSE; -- of WITH ENDLOOP; END; Peep4: PROC = BEGIN -- PUTs and PUSHs, RF and WF to RSTR and WSTR OPEN FOpCodes; ci: CCIndex; next: CCIndex ← start; state: PeepState; canSlide: BOOLEAN ← FALSE; UNTIL (ci ← next) = CCNull DO next ← NextInteresting[ci]; WITH cb[ci] SELECT FROM code => BEGIN OPEN state; IF canSlide THEN SlidePeepState2[@state, LOOPHOLE[ci]] ELSE InitParameters[@state, LOOPHOLE[ci], abc]; canSlide ← FALSE; SELECT cInst FROM qLL => IF bInst = qSL AND cP[1] = bP[1] THEN IF cP[1] IN LocalPutSlots THEN {cb[b].inst ← qPL; P5U.DeleteCell[c]} ELSE {CPtr.codeptr ← b; P5.C0[qPUSH]; P5U.DeleteCell[c]} ELSE canSlide ← TRUE; qPUSH => IF bInst = qSL AND bP[1] IN LocalPutSlots THEN {cb[b].inst ← qPL; P5U.DeleteCell[c]} ELSE canSlide ← TRUE; qLG => IF bInst = qSG AND cP[1] = bP[1] THEN {CPtr.codeptr ← b; P5.C0[qPUSH]; P5U.DeleteCell[c]} ELSE canSlide ← TRUE; qRIL => IF bInst = qWIL AND cP[1] = bP[1] AND cP[2] = bP[2] THEN {CPtr.codeptr ← b; P5.C0[qPUSH]; P5U.DeleteCell[c]} ELSE canSlide ← TRUE; qRILL => IF bInst = qWILL AND cP[1] = bP[1] AND cP[2] = bP[2] THEN {CPtr.codeptr ← b; P5.C0[qPUSH]; P5U.DeleteCell[c]} ELSE canSlide ← TRUE; qRIGL => IF bInst = qWIGL AND cP[1] = bP[1] AND cP[2] = bP[2] THEN {CPtr.codeptr ← b; P5.C0[qPUSH]; P5U.DeleteCell[c]} ELSE canSlide ← TRUE; qRF, qWF, qRFL, qWFL => BEGIN position, size: [0..16); [position, size] ← UnpackFD[LOOPHOLE[cP[2]]]; IF size = 8 AND cP[1] <= LAST[Byte]/2 THEN SELECT position FROM 0, 8 => BEGIN P5.LoadConstant[0]; P5.C1[(SELECT cInst FROM qRF => qRSTR, qWF => qWSTR, qRFL => qRSTRL, ENDCASE => qWSTRL), cP[1]*2+position/8]; P5U.DeleteCell[c]; END; ENDCASE => canSlide ← TRUE ELSE canSlide ← TRUE; END; ENDCASE => canSlide ← TRUE; END; -- of OPEN state ENDCASE => canSlide ← FALSE; -- of WITH ENDLOOP; END; NonWS: ARRAY [FOpCodes.qWS..FOpCodes.qWSD] OF Byte = [ FOpCodes.qW, FOpCodes.qWF, FOpCodes.qWD]; Peep5: PROC = BEGIN -- put doubles back, eliminate EXCH preceding commutative operator OPEN FOpCodes; ci: CCIndex; next: CCIndex ← start; state: PeepState; canSlide: BOOLEAN ← FALSE; UNTIL (ci ← next) = CCNull DO next ← NextInteresting[ci]; WITH cc:cb[ci] SELECT FROM code => BEGIN OPEN state; IF canSlide THEN SlidePeepState2[@state, LOOPHOLE[ci]] ELSE InitParameters[@state, LOOPHOLE[ci], abc]; canSlide ← FALSE; SELECT cInst FROM qLL => IF bInst = qLL AND cP[1] = bP[1]+1 THEN {cb[b].inst ← qLLD; P5U.DeleteCell[c]} ELSE GO TO Slide; qSL => IF bInst = qSL AND cP[1] = bP[1]-1 THEN {cb[c].inst ← qSLD; P5U.DeleteCell[b]} ELSE GO TO Slide; qLG => IF bInst = qLG AND cP[1] = bP[1]+1 THEN {cb[b].inst ← qLGD; P5U.DeleteCell[c]} ELSE GO TO Slide; qSG => IF bInst = qSG AND cP[1] = bP[1]-1 THEN {cb[c].inst ← qSGD; P5U.DeleteCell[b]} 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 AND ~NextIsPush[c] THEN {P5U.DeleteCell[b]; cc.inst ← NonWS[cInst]} 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; -- of OPEN state jump => BEGIN canSlide ← FALSE; IF cc.jtype IN [JumpE..UJumpLE] THEN BEGIN prev: CCIndex ← PrevInteresting[ci]; WITH cb[prev] SELECT FROM code => IF ~realinst AND inst = qEXCH AND ~PushFollows[LOOPHOLE[ci,JumpCCIndex]] THEN {P5U.DeleteCell[prev]; cc.jtype ← RJump[cc.jtype]}; ENDCASE; END; END; ENDCASE => canSlide ← FALSE; -- of WITH ENDLOOP; END; PushFollows: PROC [c: JumpCCIndex] RETURNS [BOOLEAN] = BEGIN -- c is conditional jump; TRUE if PUSH follows on either branch next: CCIndex; FOR next ← NextInteresting[c], NextInteresting[next] 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←NextInteresting[cb[c].destlabel]) # CCNull THEN WITH cb[next] SELECT FROM code => IF ~realinst AND inst = FOpCodes.qPUSH THEN RETURN [TRUE]; ENDCASE; RETURN [FALSE] END; NextIsPush: PROC [c: CCIndex] RETURNS [BOOLEAN] = BEGIN -- c is conditional jump; TRUE if PUSH follows on either branch FOR next: CCIndex ← NextInteresting[c], NextInteresting[next] 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; RETURN [FALSE] END; CommuteCells: PROC [a, b: CCIndex] = BEGIN -- could be a "source other CCItem" between, -- in any case, move a to after b -- see 3/5/80 notes for rationale aPrev: CCIndex = cb[a].blink; -- never Null aNext: CCIndex = cb[a].flink; -- probably b bPrev: CCIndex = cb[b].blink; -- probably a bNext: CCIndex = cb[b].flink; cb[aPrev].flink ← aNext; cb[aNext].blink ← aPrev; cb[b].flink ← a; cb[a].blink ← b; cb[a].flink ← bNext; IF bNext # CCNull THEN cb[bNext].blink ← a; END; Peep6: PROC = BEGIN -- store double/load double, INC and DEC, MUL to SHIFT etc OPEN FOpCodes; ci: CCIndex; next: CCIndex ← start; canSlide: BOOLEAN ← FALSE; state: PeepState; negate: BOOLEAN; D2: PROC = {Delete2[state.b, state.c]; IF negate THEN P5.C0[qNEG]}; UNTIL (ci ← next) = CCNull DO next ← NextInteresting[ci]; WITH cb[ci] SELECT FROM code => BEGIN OPEN state; IF canSlide THEN SlidePeepState1[@state, LOOPHOLE[ci]] ELSE InitParameters[@state, LOOPHOLE[ci], bc]; canSlide ← FALSE; SELECT cInst FROM qLLD => IF bInst = qSLD AND cP[1] = bP[1] THEN BEGIN CPtr.codeptr ← b; IF cP[1] IN LocalPutSlots THEN {P5.C1[qSL, cP[1]+1]; P5.C1[qPL, cP[1]]; P5.C0[qPUSH]; Delete2[b,c]} ELSE {P5.C0[qPUSH]; P5.C0[qPUSH]; P5U.DeleteCell[c]}; END ELSE GO TO Slide; qLGD => IF bInst = qSGD AND cP[1] = bP[1] THEN {CPtr.codeptr ← b; P5.C0[qPUSH]; P5.C0[qPUSH]; P5U.DeleteCell[c]} 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 {cb[c].inst ← qINC; P5U.DeleteCell[b]}; -1 => IF cInst = qSUB THEN {cb[c].inst ← qINC; P5U.DeleteCell[b]}; ENDCASE => GO TO Slide; END ELSE IF bInst = qNEG THEN {cb[c].inst ← IF cInst = qADD THEN qSUB ELSE qADD; P5U.DeleteCell[b]} ELSE GO TO Slide; qSHIFT => IF bInst = qLI THEN SELECT bP[1] FROM 1 => {cb[c].inst ← qDBL; P5U.DeleteCell[b]}; 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 {negate ← TRUE; bP[1] ← -LOOPHOLE[bP[1], INTEGER]}; SELECT bP[1] FROM 1 => D2[]; 2 => {P5.C0[qDBL]; D2[]}; 3 => {P5.C0[qDUP]; P5.C0[qDBL]; MC0[qADD, cMin]; D2[]}; 4 => {P5.C0[qDBL]; P5.C0[qDBL]; D2[]}; 5 => {P5.C0[qDUP]; P5.C0[qDBL]; P5.C0[qDBL]; MC0[qADD, cMin]; D2[]}; 6 => {P5.C0[qDBL]; P5.C0[qDUP]; P5.C0[qDBL]; MC0[qADD, cMin]; D2[]}; ENDCASE => BEGIN powerOf2: BOOLEAN; log: CARDINAL; [powerOf2, log] ← Log2[LOOPHOLE[bP[1]]]; IF powerOf2 THEN {P5.LoadConstant[log]; P5.C0[qSHIFT]; D2[]} ELSE GO TO Slide; END; END; ENDCASE => GO TO Slide; EXITS Slide => canSlide ← TRUE; END; -- of OPEN state ENDCASE => canSlide ← FALSE; -- of WITH ENDLOOP; END; Log2: PROC [i: INTEGER] RETURNS [BOOLEAN, CARDINAL] = BEGIN OPEN Inline; IF i = 0 THEN RETURN [FALSE, 0]; i ← ABS[i]; IF BITAND[i, i-1] # 0 THEN RETURN [FALSE, 0]; FOR shift: CARDINAL 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: PROC = BEGIN -- find special jumps OPEN FOpCodes; ci: CCIndex; next: CCIndex ← start; jstate: JumpPeepState; UNTIL (ci ← next) = CCNull DO next ← NextInteresting[ci]; WITH cb[ci] SELECT FROM jump => BEGIN OPEN jstate; InitJParametersBC[@jstate, LOOPHOLE[ci]]; SELECT jtype FROM JumpE => IF bInst = qLI AND bP[1] = 0 THEN {jtype ← ZJumpE; P5U.DeleteCell[b]}; JumpN => IF bInst = qLI AND bP[1] = 0 THEN {jtype ← ZJumpN; P5U.DeleteCell[b]}; ENDCASE; END; -- of OPEN jstate ENDCASE; -- of WITH ENDLOOP; END; END.